Java8对读写锁的改进:StampedLock

该类是一个读写锁的改进,它的思想是读写锁中读不仅不阻塞读,同时也不应该阻塞写。

        读不阻塞写的实现思路:

        在读的时候如果发生了写,则应当重读而不是在读的时候直接阻塞写!

        因为在读线程非常多而写线程比较少的情况下,写线程可能发生饥饿现象,也就是因为大量的读线程存在并且读线程都阻塞写线程,

因此写线程可能几乎很少被调度成功!当读执行的时候另一个线程执行了写,则读线程发现数据不一致则执行重读即可。所以读写都存在的情况下,

使用StampedLock就可以实现一种无障碍操作,即读写之间不会阻塞对方,但是写和写之间还是阻塞的!

     

        程序举例:

 public  class  Point {

           //一个点的x,y坐标

           private   double   x,y;

           /**Stamped类似一个时间戳的作用,每次写的时候对其+1来改变被操作对象的Stamped值

            * 这样其它线程读的时候发现目标对象的Stamped改变,则执行重读*/

           private final   StampedLock  stampedLock   =  new    StampedLock();

  

           // an exclusively locked method

           void move(doubledeltaX,doubledeltaY) {

                   /**stampedLock调用writeLock和unlockWrite时候都会导致stampedLock的stamp值的变化

                  * 即每次+1,直到加到最大值,然后从0重新开始 */

                  longstamp =stampedLock.writeLock(); //写锁

                  try {

                         x +=deltaX;

                         y +=deltaY;

                  } finally {

                         stampedLock.unlockWrite(stamp);//释放写锁

                  }

           }

  

         double distanceFromOrigin() {    // A read-only method

                 /**tryOptimisticRead是一个乐观的读,使用这种锁的读不阻塞写

                 * 每次读的时候得到一个当前的stamp值(类似时间戳的作用)*/

                longstamp =stampedLock.tryOptimisticRead();

     

                //这里就是读操作,读取x和y,因为读取x时,y可能被写了新的值,所以下面需要判断

                double    currentX =x,   currentY =y;

     

                /**如果读取的时候发生了写,则stampedLock的stamp属性值会变化,此时需要重读,

                * 再重读的时候需要加读锁(并且重读时使用的应当是悲观的读锁,即阻塞写的读锁)

                 * 当然重读的时候还可以使用tryOptimisticRead,此时需要结合循环了,即类似CAS方式

                 * 读锁又重新返回一个stampe值*/

                if (!stampedLock.validate(stamp)) {

                        stamp =stampedLock.readLock(); //读锁

                        try {

                              currentX =x;

                              currentY =y;

                        }finally{

                              stampedLock.unlockRead(stamp);//释放读锁

                       }

                }

               //读锁验证成功后才执行计算,即读的时候没有发生写

               return Math.sqrt(currentX *currentX + currentY *currentY);

          }

}

        StampedLock的实现思想

        在StampedLock中使用了CLH自旋锁,如果发生了读失败,不立刻把读线程挂起,锁当中维护了一个等待线程队列。

所有申请锁但是没有成功的线程都会记录到这个队列中,每一个节点(一个节点表示一个线程)保存一个标记位(locked),

用于判断当前线程是否已经释放锁。当一个未标记到队列中的线程试图获得锁时,会取得当前等待队列尾部的节点作为其前序节点,

并使用类似如下代码(一个空的死循环)判断前序节点是否已经成功的释放了锁:

        while(pred.locked){  }   

        解释:pred表示当前试图获取锁的线程的前序节点,如果前序节点没有释放锁,则当前线程就执行该空循环并不断判断前序节点的锁释放,

即类似一个自旋锁的效果,避免被系统挂起。当循环一定次数后,前序节点还没有释放锁,则当前线程就被挂起而不再自旋,

因为空的死循环执行太多次比挂起更消耗资源。

————————————————
版权声明:本文为CSDN博主「单曲循环的寂寞」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/sunfeizhi/article/details/52135136

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值