Java并发 -- StampedLock

栏目: Java · 发布时间: 6年前

  1. StampedLock同样适用于 读多写少 的场景,性能比ReadWriteLock好
  2. ReadWriteLock支持两种模式: 写锁读锁
  3. StampedLock支持三种模式: 写锁悲观读锁 乐观读 (关键)
    • StampedLock的 写锁、悲观读锁 的语义和ReadWriteLock的 写锁、读锁 的语义非常 类似
      • 允许多个线程同时获取悲观读锁,只允许一个线程获取写锁,写锁和悲观读锁是 互斥
    • 但StampedLock里的写锁和悲观读锁加锁成功之后,都会返回一个 stamp ,然后解锁的时候需要传入这个stmap
public class StampedLockExample {
    private final StampedLock stampedLock = new StampedLock();

    @Test
    // 悲观读锁
    public void pessimisticReadLockTest() {
        long stamp = stampedLock.readLock();
        try {
            // 业务逻辑
        } finally {
            stampedLock.unlockRead(stamp);
        }
    }

    @Test
    // 写锁
    public void writeLockTest() {
        long stamp = stampedLock.writeLock();
        try {
            // 业务逻辑
        } finally {
            stampedLock.unlockWrite(stamp);
        }
    }
}

乐观读

  1. StampedLock的性能比ReadWriteLock要好的关键是StampedLock支持 乐观读 的方式
  2. ReadWriteLock支持多个线程同时读,但当多个线程同时读的时候,所有写操作都会被阻塞
  3. StampedLock提供的乐观读,是 允许一个线程获取写锁 的,并不是所有的写操作都会被阻塞
  4. 乐观读这个操作是 无锁 的,相对于ReadWriteLock的读锁,乐观读的性能要更好一点
public class Point {
    private int x, y;
    private final StampedLock stampedLock = new StampedLock();

    // 计算到原点的距离
    public double distanceFromOrigin() {
        // 乐观锁(无锁算法,共享变量x和y读入方法局部变量时,x和y有可能被其他线程修改)
        long stamp = stampedLock.tryOptimisticRead();
        // 读入局部变量,读的过程中,数据可能被修改
        int curX = x;
        int curY = y;
        // 判断执行读操作期间,是否存在写操作,如果存在,validate会返回false
        if (!stampedLock.validate(stamp)) {
            // 升级为悲观读锁
            // 如果不升级,有可能反复执行乐观读,浪费大量CPU
            stamp = stampedLock.readLock();
            try {
                curX = x;
                curY = y;
            } finally {
                // 释放悲观读锁
                stampedLock.unlockRead(stamp);
            }
        }
        return Math.sqrt(curX * curX + curY * curY);
    }
}

数据库的乐观锁

-- 假设version=9
SELECT id,...,version FROM product_doc WHERE id=777;

-- version类似于StampedLock的stamp
UPDATE product_doc SET version=version+1,... WHERE id=777 AND version=9;

注意事项

  1. StampedLock的功能仅仅是ReadWriteLock的 子集
  2. StampedLock在命名上并没有增加Reentrant关键字, 不支持重入
  3. StampedLock的 悲观读锁、写锁 都不支持 条件变量
  4. 假设线程阻塞在StampedLock的 readLock 或者 writeLock
    • 如果此时调用该阻塞线程的 interrupt ,会导致 CPU飙升
  5. 使用StampedLock 不要调用中断操作
    • 如果需要支持中断功能,使用 可中断readLockInterruptiblywriteLockInterruptibly
StampedLock lock = new StampedLock();
Thread t1 = new Thread(() -> {
    // 获取写锁
    lock.writeLock();
    // 永远阻塞,不释放写锁
    LockSupport.park();
});
t1.start();
// 保证t1获得写锁
TimeUnit.SECONDS.sleep(1);

Thread t2 = new Thread(() -> {
    // 阻塞在悲观读锁
    lock.readLock();
});
t2.start();
// 保证t2阻塞在悲观读锁
TimeUnit.SECONDS.sleep(1);

// 导致t2所在的CPU飙升
t2.interrupt();
t2.join();

转载请注明出处:http://zhongmingmao.me/2019/05/10/java-concurrent-stamped-lock/

访问原文「 Java并发 -- StampedLock 」获取最佳阅读体验并参与讨论


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Where Wizards Stay Up Late

Where Wizards Stay Up Late

Katie Hafner / Simon & Schuster / 1998-1-21 / USD 16.00

Twenty five years ago, it didn't exist. Today, twenty million people worldwide are surfing the Net. "Where Wizards Stay Up Late" is the exciting story of the pioneers responsible for creating the most......一起来看看 《Where Wizards Stay Up Late》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

SHA 加密
SHA 加密

SHA 加密工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具