java 使用ConcurrentHashMap和计数器实现锁
java使用ConcurrentHashMap和计数器实现锁
在某些场景下,我们想让线程根据某些业务数据进行排队,简单代码如下:
importjava.util.ArrayList; importjava.util.HashMap; importjava.util.List; importjava.util.Map; importjava.util.concurrent.ConcurrentHashMap; importjava.util.concurrent.atomic.AtomicInteger; publicclassTestServiceImpl{ privatestaticConcurrentHashMaplockMap=newConcurrentHashMap (40); publicvoidtest(LonguserId){ LockObjlock=tryLock(userId); synchronized(lock){ try{ //处理业务 } finally{ unLock(lock); } } } privateLockObjtryLock(Longkey){ LockObjcurVal=newLockObj(key); LockObjpreVal=lockMap.putIfAbsent(key,curVal); if(null==preVal){ curVal.inc(); returncurVal; } else{ preVal.inc(); } returnpreVal; } privatevoidunLock(LockObjlock){ if(lock.dec()<=0){ lockMap.remove(lock.getKey()); } } publicclassLockObj{ privatelongkey=0; privateAtomicIntegercount=newAtomicInteger(0); publicLockObj(longkey){ this.key=key; } publicintinc(){ returncount.incrementAndGet(); } publicintdec(){ returncount.decrementAndGet(); } publiclonggetKey(){ returnkey; } @Override publicStringtoString(){ return"LockObj[key="+key+",count="+count+"]"; } } }
按照userId来排队,如果每个线程处理数据后不释放锁的话,那么可以不利用计数器。但是加了释放锁的操作,则必须加上计算器。因为当线程把锁释放掉后,还没来得及退出synchronized代码块时,另外一个线程调用了tryLock方法,那该线程将拿到另外一个对象的锁,导致利用synchronized关键字进行userId排队失败。
也可以利用guava的API来实现。
importcom.google.common.collect.Interner; importcom.google.common.collect.Interners; publicclassTestServiceImpl{ Internerpool=Interners.newWeakInterner(); publicvoidtest(LonguserId)throwsOspException{ synchronized(pool.intern(String.valueOf(userId))){ //处理业务操作 } } }
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!