该类自JDK8加入,是为了进一步优化读性能,他的特点是在使用读锁、写锁时都必须配合【戳】使用
加解读锁
long stamp = lock.readLock();
lock.unlockRead(stamp);
加解写锁
long stamp = lock.writeLock();
lock.unlockWrite(stamp);
乐观读,StampedLock支持typeOptimisticRead()
方法(乐观读),读取完毕之后需要做一次戳校验
,如果校验通过,表示这期间确实没有写操作,数据可以安全使用,如果校验没通过,需要重新获取读锁,保证数据安全。
long stamp = lock.tryOptimisticRead();
// 验戳
if(!lock.validate(stamp)){
// 锁升级
}
提供一个数据容器类,内部分别使用读锁保护数据的read()
方法,写锁保护数据的write()
方法
public class DataContainerStamped {
private int data;
private final StampedLock lock = new StampedLock();
public DataContainerStamped(int data) {
this.data = data;
}
public int read(long readTime) throws InterruptedException {
long stamp = lock.tryOptimisticRead();
log.debug("optimistic locking {}", stamp);
Thread.sleep(readTime);
if (lock.validate(stamp)) {
log.debug("read finish {}, data {}", stamp, data);
return data;
}
log.debug("updating to read lock {}", stamp);
try {
stamp = lock.readLock();
log.debug("read lock {}", stamp);
Thread.sleep(readTime);
log.debug("read finish {}, data {}", stamp, data);
return data;
} finally {
log.debug("read unlock {}", stamp);
lock.unlockRead(stamp);
}
}
public void write(int newData) {
long stamp = lock.writeLock();
log.debug("write lock {}", stamp);
try {
Thread.sleep(2000);
this.data = newData;
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
log.debug("write unlock {}", stamp);
lock.unlockWrite(stamp);
}
}
}
测试读-读
可以优化
public static void main(String[] args) throws InterruptedException {
DataContainerStamped dataContainerStamped = new DataContainerStamped(1);
new Thread(() -> {
try {
dataContainerStamped.read(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "t1").start();
Thread.sleep(500);
new Thread(() -> {
try {
dataContainerStamped.read(0);
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "t2").start();
}
输出结果,可以看到实际没有加锁
2022/05/15-14:10:31.150 [t1] c.DataContainerStamped - optimistic locking 256
2022/05/15-14:10:31.658 [t2] c.DataContainerStamped - optimistic locking 256
2022/05/15-14:10:31.658 [t2] c.DataContainerStamped - read finish 256, data 1
2022/05/15-14:10:32.157 [t1] c.DataContainerStamped - read finish 256, data 1
测试读-写
时优化读补加读锁
public static void main(String[] args) throws InterruptedException {
DataContainerStamped dataContainerStamped = new DataContainerStamped(1);
new Thread(() -> {
try {
dataContainerStamped.read(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "t1").start();
Thread.sleep(500);
new Thread(() -> {
dataContainerStamped.write(100);
}, "t2").start();
}
输出结果
2022/05/15-14:19:05.928 [t1] c.DataContainerStamped - optimistic locking 256
2022/05/15-14:19:06.441 [t2] c.DataContainerStamped - write lock 384
2022/05/15-14:19:06.937 [t1] c.DataContainerStamped - updating to read lock 256
2022/05/15-14:19:08.441 [t2] c.DataContainerStamped - write unlock 384
2022/05/15-14:19:08.441 [t1] c.DataContainerStamped - read lock 513
2022/05/15-14:19:09.452 [t1] c.DataContainerStamped - read finish 513, data 100
2022/05/15-14:19:09.452 [t1] c.DataContainerStamped - read unlock 513
注意
- StampedLock不支持条件变量
- StampedLock不支持可重入