- StampedLock同样适用于 读多写少 的场景,性能比ReadWriteLock好
- ReadWriteLock支持两种模式: 写锁 、 读锁
-
StampedLock支持三种模式: 写锁
、 悲观读锁
、
乐观读
(关键)
-
StampedLock的 写锁、悲观读锁
的语义和ReadWriteLock的 写锁、读锁
的语义非常 类似
- 允许多个线程同时获取悲观读锁,只允许一个线程获取写锁,写锁和悲观读锁是 互斥 的
- 但StampedLock里的写锁和悲观读锁加锁成功之后,都会返回一个 stamp ,然后解锁的时候需要传入这个stmap
-
StampedLock的 写锁、悲观读锁
的语义和ReadWriteLock的 写锁、读锁
的语义非常 类似
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);
}
}
}
乐观读
- StampedLock的性能比ReadWriteLock要好的关键是StampedLock支持 乐观读 的方式
- ReadWriteLock支持多个线程同时读,但当多个线程同时读的时候,所有写操作都会被阻塞
- StampedLock提供的乐观读,是 允许一个线程获取写锁 的,并不是所有的写操作都会被阻塞
- 乐观读这个操作是 无锁 的,相对于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;
注意事项
- StampedLock的功能仅仅是ReadWriteLock的 子集
- StampedLock在命名上并没有增加Reentrant关键字, 不支持重入
- StampedLock的 悲观读锁、写锁 都不支持 条件变量
-
假设线程阻塞在StampedLock的 readLock
或者 writeLock
上
- 如果此时调用该阻塞线程的 interrupt ,会导致 CPU飙升
-
使用StampedLock 不要调用中断操作
- 如果需要支持中断功能,使用 可中断 的 readLockInterruptibly 或 writeLockInterruptibly
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 」获取最佳阅读体验并参与讨论
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- Java并发系列—并发编程基础
- [Java并发-17-并发设计模式] Immutability模式:如何利用不变性解决并发问题?
- JAVA并发编程之并发模拟工具
- Java并发系列—并发编程的挑战
- Core Java 并发:理解并发概念
- [Java并发-11] 并发容器的使用
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
深入React技术栈
陈屹 / 人民邮电出版社 / 2016-11-1 / CNY 79.00
全面讲述React技术栈的第一本原创图书,pure render专栏主创倾力打造 覆盖React、Flux、Redux及可视化,帮助开发者在实践中深入理解技术和源码 前端组件化主流解决方案,一本书玩转React“全家桶” 本书讲解了非常多的内容,不仅介绍了面向普通用户的API、应用架构和周边工具,还深入介绍了底层实现。此外,本书非常重视实战,每一节都有实际的例子,细节丰富。我从这......一起来看看 《深入React技术栈》 这本书的介绍吧!