synchronized的优化

在较早版本的JDK中使用synchronized来实现线程安全,但同时使得并发的线程变成顺序执行,对系统并发吞吐能力有极大影响,在JDK1.5以后可以对其进行优化了。

我们先来看看原始的synchronized的使用方法:

悲观锁:

public Object get(Object key) {   
   synchronized(map) {   
      if(map.get(key) == null) {   
         // set some values   
      }   
  
       return map.get(key);   
   }   
}  

 乐观锁:

public Object get(Object key) {   
   Object val = null;   
    if((val = map.get(key) == null) {   
       // if map value is null, add lock measure
       synchronized(map) {   
           if(val = map.get(key) == null) {   
               // set some value to map...   
           }   
        }   
   }   
    //get value 
    return map.get(key);   
} 

 

String.intern:

上述乐观锁中还是不能很好解决大量写冲突问题,比如一个用户必须先创建session,才能进行后续的操作,但由于网络原因创建用户session的请求和后续请求几乎同时达到,而并行线程可能会先处理后续请求。一般情况,需要对用户sessionMap加锁,比如上面的乐观锁。在这种场景下,使用String.inter()是一种更高效的办法,类 String 维护一个字符串池,当调用 intern 方法时,如果池已经包含一个等于此 String 对象的字符串(该对象由 equals(Object) 方法确定),则返回池中的字符串,可见,当String相同时,String.intern()总是返回同一个对象,因此就实现了对同一用户加锁。由于锁的粒度局限于具体用户,使系统获得了最大程度的并发:

public void doSomeThing(String uid) {   
   synchronized(uid.intern()) {   
       // ...   
   }   
} 

 

 

ConcurrentHashMap:

String.inter()的缺陷是类 String 维护一个字符串池是放在JVM perm区的,如果用户数特别多,导致放入字符串池的String不可控,有可能导致OOM错误或者过多的Full GC。怎么样能控制锁的个数,同时减小粒度锁呢?Java ConcurrentHashMap提供了一种很好的方式,将需要加锁的对象分为多个bucket,每个bucket加一个锁,伪代码如下:

Map locks = new Map();   
List lockKeys = new List();   
for(int number : 1 - 10000) {   
   Object lockKey = new Object();   
   lockKeys.add(lockKey);   
    locks.put(lockKey, new Object());   
}   
  
public void doSomeThing(String uid) {   
   Object lockKey = lockKeys.get(uid.hash() % lockKeys.size());   
   Object lock = locks.get(lockKey);         
   synchronized(lock) {   
      // do something   
   }   
}  

上述的做法相当于由全局(只有一个bucket,这个bucket加了锁后,都需要等待)锁变成了一个细粒度(多个bucket,每个bucket加一个锁,即使某个bucket加锁,但是其他bucket并没有加锁,无需等待,这样提高了并发、吞吐量),当然在java.util.concurrent包中还包含一系列的锁来处理同步的问题,比如:ReadWriteLock接口、MuTex等,这些对象在实例化以后都有类似的锁请求、锁超时、锁中断、锁释放的方法来维护锁,当然MuTex还包括了可以在不同的方法中实现锁传递(当获得/释放锁操作不能在同一个方法或者代码块中进行时候,不能使用synchronized块,这就要使用Mutex),这种情况下,要求在持有当前节点锁的同时,获得下一个节点的锁,但是,在获得下一个节点的锁之后,就可以释放当前的锁了!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值