zoukankan      html  css  js  c++  java
  • StampedLock

    1StampedLock邮戳锁支持三种模式,分别是:写锁,读锁,乐观读。

        ReentrantReadWriteLock读写锁的缺点是在读多写少的情况下,写线程会被阻塞,写线程可能会一直抢不到锁发生饥饿现象

        邮戳锁可以避免这种情况,在乐观读的时候,不会对其他的写线程阻塞,其他的线程可以获取到写锁

    2)邮戳锁的乐观读可以升级为写锁,读写锁不能由读锁升级为写锁

    (3)无论写锁还是读锁,都不支持Conditon等待

    class Point {
    
        // 成员变量
        private double x, y;
    
        // 锁实例
        private final StampedLock sl = new StampedLock();
    
        // 排它锁-写锁(writeLock)
        void move(double deltaX, double deltaY) {
            long stamp = sl.writeLock();
            try {
                x += deltaX;
                y += deltaY;
            } finally {
                sl.unlockWrite(stamp);
            }
        }
    
        // 一个只读方法
        // 其中存在乐观读锁到悲观读锁的转换
        double distanceFromOrigin() {
    
            // 尝试获取乐观读锁
            long stamp = sl.tryOptimisticRead();
            // 将全部变量拷贝到方法体栈内
            double currentX = x, currentY = y;
            // 检查在获取到读锁stamp后,锁有没被其他写线程抢占
            if (!sl.validate(stamp)) {
                // 如果被抢占则获取一个共享读锁(悲观获取)
                stamp = sl.readLock();
                try {
                    // 将全部变量拷贝到方法体栈内
                    currentX = x;
                    currentY = y;
                } finally {
                    // 释放共享读锁
                    sl.unlockRead(stamp);
                }
            }
            // 返回计算结果
            return Math.sqrt(currentX * currentX + currentY * currentY);
        }
    
        // 获取读锁,并尝试转换为写锁
        void moveIfAtOrigin(double newX, double newY) {
            long stamp = sl.tryOptimisticRead();
            try {
                // 如果当前点在原点则移动
                while (x == 0.0 && y == 0.0) {
                    // 尝试将获取的读锁升级为写锁
                    long ws = sl.tryConvertToWriteLock(stamp);
                    // 升级成功,则更新stamp,并设置坐标值,然后退出循环
                    if (ws != 0L) {
                        stamp = ws;
                        x = newX;
                        y = newY;
                        break;
                    } else {
                        // 读锁升级写锁失败则释放读锁,显示获取独占写锁,然后循环重试
                        sl.unlockRead(stamp);
                        stamp = sl.writeLock();
                    }
                }
            } finally {
                sl.unlock(stamp);
            }
        }
    }

       StampedLock的实现思想

            在StampedLock中使用了CLH自旋锁,如果发生了读失败,不立刻把读线程挂起,锁当中维护了一个等待线程队列。所有申请锁但是没有成功的线程都会记录到这个队列中,每一个节点(一个节点表示一个线程)保存一个标记位(locked),用于判断当前线程是否已经释放锁。新加入的节点会加入到队列的末尾,当前等待队列尾部的节点作为其前序节点,并使用类似如下代码(一个空的死循环)判断前序节点是否已经成功的释放了锁: while(pred.locked){  }   

            解释:pred表示当前试图获取锁的线程的前序节点,如果前序节点没有释放锁,则当前线程就执行该空循环并不断判断前序节点的锁释放,即类似一个自旋锁的效果,避免被系统挂起。当循环一定次数后,前序节点还没有释放锁,则当前线程就被挂起而不再自旋

  • 相关阅读:
    函数的运用
    CSS颜色透明渐变
    白手起家:推广网站二十四招
    关于真正免费下载铃声
    改变生活的方法
    Hang in there,just for you
    写的浪漫
    计算机常用词汇IT开发
    马云在《赢在中国》对创业者的经典点评
    怎样才能把自己的网站做好(引用经济学理论知识)[转]
  • 原文地址:https://www.cnblogs.com/moris5013/p/11882894.html
Copyright © 2011-2022 走看看