Java并发 -- StampedLock

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

  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 」获取最佳阅读体验并参与讨论


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

查看所有标签

猜你喜欢:

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

人月神话(40周年中文纪念版)

人月神话(40周年中文纪念版)

(美) 布鲁克斯(Brooks, F. P.) 著 / UML China翻译组,汪颖 译 / 清华大学出版社 / 2015-4-1 / 68.00元

在软件领域,很少能有像《人月神话》一样具有深远影响力和畅销不衰的著作。Brooks博士为人们管理复杂项目提供了最具洞察力的见解,既有很多发人深省的观点,又有大量软件工程的实践。本书内容来自Brooks博士在IBM公司SYSTEM/360家族和OS/360中的项目管理经验,该项目堪称软件开发项目管理的典范。该书英文原版一经面世,即引起业内人士的强烈反响,后又译为德、法、日、俄、中、韩等多种文字,全球......一起来看看 《人月神话(40周年中文纪念版)》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具