构建高性能服务(二)java高并发锁…


提高系统并发吞吐能力是构建高性能服务的重点和难点。通常review代码时看到synchronized是我都会想一想,这个地方可不可以优化。使用synchronized使得并发的线程变成顺序执行,对系统并发吞吐能力有极大影响,我的博文 http://maoyidao.iteye.com/blog/1149015 介绍了可以从理论上估算系统并发处理能力的方法。

 

那么对于必须使用synchronized的业务场景,这里提供几个小技巧,帮助大家减小锁粒度,提高系统并发能力。

 

初级技巧 - 乐观锁

乐观锁适合这样的场景:读不会冲突,写会冲突。同时读的频率远大于写。

 

以下面的代码为例,悲观锁的实现:

 

  1. public Object get(Object key) {   
  2.    synchronized(map) {   
  3.       if(map.get(key) == null{   
  4.          // set some values   
  5.       }   
  6.   
  7.        return map.get(key);   
  8.    }   
  9.  

  1. public Object get(Object key)  
  2.    synchronized(map)  
  3.       if(map.get(key) == null 
  4.          // set some values  
  5.        
  6.   
  7.        return map.get(key);  
  8.     
  9.  
 

 乐观锁的实现:


  1. public Object get(Object key) {   
  2.    Object val null;   
  3.    if((val map.get(key) == null{   
  4.        // 当map取值为null时再加锁判断   
  5.        synchronized(map) {   
  6.            if(val map.get(key) == null{   
  7.                // set some value to map...   
  8.            }   
  9.         }   
  10.    }   
  11.   
  12.     return map.get(key);   
  13.  

  1. public Object get(Object key)  
  2.    Object val null 
  3.    if((val map.get(key) == null 
  4.        // 当map取值为null时再加锁判断  
  5.        synchronized(map)  
  6.            if(val map.get(key) == null 
  7.                // set some value to map...  
  8.             
  9.          
  10.     
  11.   
  12.     return map.get(key);  
  13.  

 

中级技巧 - String.intern()

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

 


  1. public void doSomeThing(String uid) {   
  2.    synchronized(uid.intern()) {   
  3.        // ...   
  4.    }   
  5.  

  1. public void doSomeThing(String uid)  
  2.    synchronized(uid.intern())  
  3.        // ...  
  4.     
  5.  

 高级技巧 - 类ConcurrentHashMap

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


  1. Map locks new Map();   
  2. List lockKeys new List();   
  3. for(int number 1 10000{   
  4.    Object lockKey new Object();   
  5.    lockKeys.add(lockKey);   
  6.     locks.put(lockKey, new Object());   
  7. }   
  8.   
  9. public void doSomeThing(String uid) {   
  10.    Object lockKey lockKeys.get(uid.hash() lockKeys.size());   
  11.    Object lock locks.get(lockKey);   
  12.       
  13.    synchronized(lock) {   
  14.       // do something   
  15.    }   
  16.  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值