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))){
//处理业务操作
}
}
}
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!