java进阶笔记线程与并发之StampedLock

简介

  • StampedLock 是ReadWriteLock的一种实现,不支持重入(容易死锁),适用于读多写少的场景。

  • StampedLock 在读取的节点是并发唤醒的,在读取上的性能理论上更高。

  • 一旦读写操作在1:1甚至以上,则synchronized的性能将更高,ReentrantReadWriteLock的性能急剧下降,StampedLock 性能缓慢下降。一般推荐使用synchronized,而读取占比非常高的常见建议自定义乐观锁实现。

  • 方法

    • long writeLock() 阻塞获取排它写锁

    • tryWriteLock() 尝试获取排它写锁

    • public long tryWriteLock(long time, TimeUnit unit)

    • public long writeLockInterruptibly() throws InterruptedException

    • public long readLock() 读锁,非排它

    • public long tryOptimisticRead() 尝试乐观方式获取读取锁,当成功返回一个stamp,否则返回0L

    • public boolean validate(long stamp)

      • 持有锁或者改stamp未被独占则返回true
      • 如果 stamp == 0 ,则返回false
    • public long tryConvertToWriteLock(long stamp)

    • 如果锁状态与给定的戳记匹配,则执行以下操作之一。如果戳记表示持有写锁,则返回它。或者,如果有读锁,如果写锁可用,则释放读锁并返回写戳。或者,如果是乐观读,则仅在立即可用时才返回写戳记。此方法在所有其他情况下都返回零。

  • public long tryConvertToReadLock(long stamp)

    • public long tryConvertToOptimisticRead(long stamp)
    • 如果锁状态与给定的戳记匹配,则执行以下操作之一。如果戳记表示持有写锁,则释放它并获得读锁。或者,如果是读锁,则返回它。或者,如果一个乐观读操作获得了一个读锁,并且只有在立即可用的情况下才返回一个读戳。此方法在所有其他情况下都返回零。

使用示例

官方示例:

class Point {
    private double x, y;
    private final StampedLock sl = new StampedLock();
 
    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;
        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) {
        // Could instead start with optimistic, not read mode
        long stamp = sl.readLock();
        try {
            while (x == 0.0 && y == 0.0) {
                long ws = sl.tryConvertToWriteLock(stamp);
                if (ws != 0L) {
                    //转换成功则使用返回的stamp
                    stamp = ws;
                    x = newX;
                    y = newY;
                    break;
                } else {
                    sl.unlockRead(stamp);
                    stamp = sl.writeLock();
                }
            }
        } finally {
            sl.unlock(stamp);
        }
    }
}

想法

  • 对于有顺序要求的数据处理,可以使用排队机制(同锁里面的链表、队列)
  • 对于冲突的线程,避免频繁尝试获取独占资源,采用获取资格后排队处理
  • 独占和非独占操作共同处理时,独占阻塞其它所有处理,非独占则唤醒所有非独占操作。

注: 找到一个文章将原理说的详细明了,见参见。

参见

java多线程进阶(十一)—— J.U.C之locks框架:StampedLock: https://segmentfault.com/a/1190000015808032?utm_source=tag-newest

Java 8 StampedLock,ReadWriteLock以及synchronized的比较: https://zhuanlan.zhihu.com/p/33422168

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值