- 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] 并发容器的使用
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
C语言从入门到精通
王娣//韩旭 / 清华大学 / 2010-7 / 49.80元
《C语言从入门到精通》从初学者的角度出发,以通俗易懂的语言,丰富多彩的实例,详细介绍了使用C语言进行程序开发应该掌握的各方面知识。全书共分17章,包括C语言概述,算法,数据类型,运算符与表达式,常用的数据输入、输出函数,选择结构程序设计,循环控制,数组,函数,指针,结构体和共用体,位运算,预处理,文件,存储管理,网络套接字编程和学生成绩管理系统等。所有知识都结合具体实例进行介绍,涉及的程序代码给出......一起来看看 《C语言从入门到精通》 这本书的介绍吧!