StampedLock锁
StampedLock是JDK1.8中新增的一个读写锁,也是对JDK1.5中的读写锁ReentrantReadWrii@Lock的优化。
1. 简介
邮戳锁又称为票据锁,stamp代表了锁的状态。当stamp返回零时,表示线程获取锁失败。并且,当释放锁或者转换锁的时候,都要传入最初获取的stamp值。
2. 特点
- 所有获取锁的方法,都返回一个邮戳(Stamp), Stamp为零表示获取失败,其余都表示成功
- 所有释放锁的方法,都需要一个邮戳(Stamp), 这个Stamp必须是和成功获取锁时得到的Stamp一致
- StampedLock是不可重入的,危险(如果一个线程已经持有了写锁,再去获取写锁的话就会造成死锁)
3. 3种模式
①Reading(读模式悲观):功能和ReentrantReadWriteLock的读锁类似
②Writing(写模式):功能和ReentrantReadWriteLock的写锁类似
③Optimistic reading(乐观读模式):无锁机制,类似于数据库中的乐观锁,支持读写并发,很乐观认为读取时没人修改,假如被修改再实现升级为悲观读模式式
4. 读写模式
java
public class TimestampLockDemo {
private static int number = 50;
StampedLock stampedLock = new StampedLock();
public void write() {
long timestamp = stampedLock.writeLock();
try {
System.out.println("修改数据。。。");
number = 37;
} finally {
stampedLock.unlockWrite(timestamp);
}
System.out.println("数据修改结束。。。");
}
public void read() throws InterruptedException {
long timestamp = stampedLock.readLock();
try{
TimeUnit.SECONDS.sleep(4);
System.out.println("读取到数据为:" + number);
}finally {
stampedLock.unlockRead(timestamp);
}
System.out.println("数据读取结束。。。");
}
public static void main(String[] args) {
TimestampLockDemo lockDemo = new TimestampLockDemo();
new Thread(() -> {
try {
lockDemo.read();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}).start();
new Thread(() -> {
lockDemo.write();
}).start();
}
}
运行结果:
5. 乐观读模式
java
public class StampLockDemo {
private static int number = 50;
StampedLock stampedLock = new StampedLock();
public void write() {
long timestamp = stampedLock.writeLock();
try {
System.out.println("修改数据。。。");
number = 37;
} finally {
stampedLock.unlockWrite(timestamp);
}
System.out.println("数据修改结束。。。");
}
public void optimisticRead() throws InterruptedException {
// 乐观读是一种无锁的读模式,不会真正获取锁,不存在解锁的操作
long timestamp = stampedLock.tryOptimisticRead();
if (!stampedLock.validate(timestamp)) {
System.out.println("数据已经被修改....");
timestamp = stampedLock.readLock();
System.out.println("从乐观读升级为悲观读");
try {
TimeUnit.SECONDS.sleep(4);
System.out.println("悲观读, 读取到数据为:" + number);
} finally {
stampedLock.unlockRead(timestamp);
}
}else{
TimeUnit.SECONDS.sleep(4);
System.out.println("读取到数据为:" + number);
}
System.out.println("数据读取结束。。。");
}
public static void main(String[] args) throws InterruptedException {
StampLockDemo lockDemo = new StampLockDemo();
new Thread(() -> {
try {
lockDemo.optimisticRead();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}).start();
// 暂停1秒
Thread.sleep(1000);
new Thread(() -> {
lockDemo.write();
}).start();
}
}
执行结果: