Chinaunix首页 | 论坛 | 博客
  • 博客访问: 83165
  • 博文数量: 31
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 340
  • 用 户 组: 普通用户
  • 注册时间: 2013-04-02 20:25
文章分类

全部博文(31)

文章存档

2015年(2)

2014年(29)

我的朋友

分类: Java

2014-08-31 20:26:48

      减少对资源的争用,是提高并发性能的关键。在并发访问中。多个读并发实际不存在线程安全问题,读写,写写并发才是线程安全问题的根源。所以读写锁应运而生。度写锁的使用并不一定都能提高并发性能,这取决于应用场景。如果写多读少,反而会造成性能的下降,因为读写锁显然比普通锁更复杂。在读多写少的场景,无疑读写锁是很好的选择。
     在JAVA的并发包中提供了一个读写锁的实现ReentrantReadWriteLock,使用起来也相当简单。如果想实现一个读写锁的话,以下几个问题是需要考虑的:
1. 读写优先级
2. 锁升级与锁降级
3. 可重入
    一个简单的读写锁实现如下:

点击(此处)折叠或打开

  1. package lock;

  2. public class RwLock {

  3.     private int nw = 0;     //获取读锁的线程数    
  4.     private int nr = 0;     //获取写锁的线程数,应该为0,1
  5.     private int nreqw = 0; //等待写锁的线程数
  6.     
  7.     public synchronized void lockRead() throws InterruptedException{
  8.         while(nw > 0 || nreqw > 0) //写优先级高,存在等待写锁线程读线程阻塞
  9.             wait();
  10.         nr++;
  11.     }
  12.     
  13.     public synchronized void unlockRead(){
  14.         nr--;
  15.         notifyAll();
  16.     }
  17.     
  18.     public synchronized void lockWrite() throws InterruptedException{
  19.         nreqw++;
  20.         while(nr > 0 || nw > 0)
  21.             wait();
  22.         nreqw--;
  23.         nw++;
  24.     }
  25.     
  26.     public synchronized void unlockWrite(){
  27.         nw--;
  28.         notifyAll();
  29.     }
  30. }
      这个实现默认写锁优先级高于读锁,但它的写锁不可重入。比如线程A获取写锁,再次请求写锁会被阻塞。解决方法是需要判断请求锁的线程是否为当前线程:

点击(此处)折叠或打开

  1. package lock;

  2. public class RwLock {

  3.     private int nw = 0;     //获取读锁的线程数    
  4.     private int nr = 0;     //获取写锁的线程数,应该为0,1
  5.     private int nreqw = 0; //等待写锁的线程数
  6.     
  7.     private Thread currentWThread = null;
  8.     
  9.     public synchronized void lockRead() throws InterruptedException{
  10.         while(nw > 0 || nreqw > 0) //写优先级高,存在等待写锁线程读线程阻塞
  11.             wait();
  12.         nr++;
  13.     }
  14.     
  15.     public synchronized void unlockRead(){
  16.         nr--;
  17.         notifyAll();
  18.     }
  19.     
  20.     public synchronized void lockWrite() throws InterruptedException{
  21.         nreqw++;
  22.         while(!canWrite())
  23.             wait();
  24.         nreqw--;
  25.         nw++;
  26.         currentWThread = Thread.currentThread();
  27.     }
  28.     
  29.     protected boolean canWrite(){
  30.         if(Thread.currentThread() == currentWThread) //写锁本就已持有
  31.             return true;
  32.         if(nr > 0 || nw > 0)
  33.             return false;
  34.         return true;
  35.     }
  36.     
  37.     
  38.     public synchronized void unlockWrite(){
  39.         nw--;
  40.         currentWThread = null;
  41.         notifyAll();
  42.     }
  43. }
      上面已经实现了写优先级高于读,读读可重入,写写可重入。但一个线程获取读锁后,再获取写锁会被阻塞,这显然不合理,这时候需要实现读写锁转换

点击(此处)折叠或打开

  1. package lock;

  2. import java.util.HashMap;
  3. import java.util.Map;

  4. public class RwLock {

  5.     private int nw = 0;     //获取读锁的线程数    
  6.     private int nreqw = 0; //等待写锁的线程数
  7.     
  8.     private Thread cwThr = null;
  9.     private Map<Thread, Integer> rThrCnts = new HashMap<Thread,Integer>();
  10.     
  11.     public synchronized void lockRead() throws InterruptedException{
  12.         while(!canRead())
  13.             wait();
  14.         Thread t = Thread.currentThread();
  15.         rThrCnts.put(t, reads(t));
  16.     }
  17.     
  18.     protected boolean canRead() {
  19.         Thread t = Thread.currentThread();
  20.         if(t == cwThr) //自己持有写锁
  21.             return true;
  22.         if(nw > 0) //其他线程持有写锁
  23.             return false;
  24.         //到此写锁未被占有,其他线程可能在等写锁,当前线程可能持有读锁
  25.         //当前持有读锁
  26.         if(rThrCnts.get(t) != null)
  27.             return true;
  28.         //当前线程未持有写锁跟读锁,写优先
  29.         if(nreqw > 0)
  30.             return false;
  31.         return true;
  32.     }
  33.     
  34.     protected int reads(Thread t) {
  35.         Integer cnt = rThrCnts.get(t).intValue();
  36.         if(cnt == null)
  37.             return 0;
  38.         return cnt.intValue();
  39.     }
  40.     
  41.     public synchronized void unlockRead(){
  42.         Thread t = Thread.currentThread();
  43.         int cnt = reads(t);
  44.         cnt--;
  45.         if(cnt == 0)
  46.             rThrCnts.remove(t);
  47.         else
  48.             rThrCnts.put(t, cnt);
  49.         notifyAll();
  50.     }
  51.     
  52.     public synchronized void lockWrite() throws InterruptedException{
  53.         nreqw++;
  54.         while(!canWrite())
  55.             wait();
  56.         nreqw--;
  57.         nw++;
  58.         cwThr = Thread.currentThread();
  59.     }
  60.     
  61.     protected boolean canWrite(){
  62.         if(Thread.currentThread() == cwThr) //写锁本就已持有
  63.             return true;
  64.         //没持有写锁,其他线程是否在写
  65.         if(nw > 0)
  66.             return false;
  67.         //其他线程没持有写锁,判断是否只有自己在读
  68.         if(rThrCnts.size() == 1 && rThrCnts.get(Thread.currentThread()) != null)
  69.             return true;
  70.         //其他线程是否在读
  71.         if(rThrCnts.size() > 0)
  72.             return false;
  73.         //没有任何线程持有读锁跟写锁
  74.         return true;
  75.     }
  76.     
  77.     public synchronized void unlockWrite(){
  78.         nw--;
  79.         cwThr = null;
  80.         notifyAll();
  81.     }
  82. }



阅读(1090) | 评论(0) | 转发(0) |
0

上一篇:10.jdbc fetchsize

下一篇:2. 分离锁

给主人留下些什么吧!~~