Java8 读写锁的改进:StampedLock(笔记)

     StampedLock是Java8引入的一种新的所机制,简单的理解,能够认为它是读写锁的一个改进版本,读写锁虽然分离了读和写的功能,使得读与读之间能够彻底并发,可是读和写之间依然是冲突的,读锁会彻底阻塞写锁,它使用的依然是悲观的锁策略.若是有大量的读线程,他也有可能引发写线程的饥饿
     而StampedLock则提供了一种乐观的读策略,这种乐观策略的锁很是相似于无锁的操做,使得乐观锁彻底不会阻塞写线程
  • StampedLock的使用实例
 
 
public class Point {
    private double x, y;//内部定义表示坐标点
    private final StampedLock s1 = new StampedLock();//定义了StampedLock锁,

    void move(double deltaX, double deltaY) {
        long stamp = s1.writeLock();//这里的含义和distanceFormOrigin方法中 s1.readLock()是相似的
        try {
            x += deltaX;
            y += deltaY;
        } finally {
            s1.unlockWrite(stamp);//退出临界区,释放写锁
        }
    }

    double distanceFormOrigin() {//只读方法
        long stamp = s1.tryOptimisticRead();  //试图尝试一次乐观读 返回一个相似于时间戳的邮戳整数stamp 这个stamp就能够做为这一个所获取的凭证
        double currentX = x, currentY = y;//读取x和y的值,这时候咱们并不肯定x和y是不是一致的
        if (!s1.validate(stamp)) {//判断这个stamp是否在读过程发生期间被修改过,若是stamp没有被修改过,责任无此次读取时有效的,所以就能够直接return了,反之,若是stamp是不可用的,则意味着在读取的过程当中,可能被其余线程改写了数据,所以,有可能出现脏读,若是若是出现这种状况,咱们能够像CAS操做那样在一个死循环中一直使用乐观锁,知道成功为止
            stamp = s1.readLock();//也能够升级锁的级别,这里咱们升级乐观锁的级别,将乐观锁变为悲观锁, 若是当前对象正在被修改,则读锁的申请可能致使线程挂起.
            try {
                currentX = x;
                currentY = y;
            } finally {
                s1.unlockRead(stamp);//退出临界区,释放读锁
            }
        }
        return Math.sqrt(currentX * currentX + currentY * currentY);
    }
}

 

  • StampedLock的小陷阱
  • 有关StampedLock的实现思想
StampedLock的内部实现是基于CLH锁的,CLH锁是一种自旋锁,它保证没有饥饿的发生,而且能够保证FIFO(先进先出)的服务顺序.
CLH锁的基本思想以下:锁维护一个等待线程队列,全部申请锁,可是没有成功的线程都记录在这个队列中,每个节点表明一个线程,保存一个标记位(locked).用与判断当前线程是否已经释放锁;locked=true 没有获取到锁,false 已经成功释放了锁
     当一个线程视图得到锁时,取得等待队列的尾部节点做为其前序节点.并使用相似以下代码判断前序节点是否已经成功释放锁:
while (pred.locked) {
   
}
     只要前序节点(pred)没有释放锁,则表示当前线程还不能继续执行,所以会自旋等待,
     反之,若是前序线程已经释放锁,则当前线程能够继续执行.
     释放锁时,也遵循这个逻辑,线程会将自身节点的locked位置标记位false,那么后续等待的线程就能继续执行了
相关文章
相关标签/搜索