StampedLock类的简介
StampedLock类,在JDK1.8时引入,是对读写锁ReentrantReadWriteLock的增强,该类提供了一些功能,优化了读锁、写锁的访问,同时使读写锁之间可以互相转换,更细粒度控制并发。它的特点是在使用读锁、写锁时都必须配合【戳】使用,如:
这个戳通常会配合该类的tryOptimisticRead方法使用,tryOptimisticRead方式采用的是乐观读的思想。在ReentrantReadWriteLock中,当读锁被使用时,如果有线程尝试获取写锁,该写线程会阻塞。但是,在Optimistic reading中,即使读线程获取到了读锁,写线程尝试获取写锁也不会阻塞,这相当于对读模式的优化,但是可能会导致数据不一致的问题。所以,当使用Optimistic reading获取到读锁时,必须对获取结果使用戳进行校验。
StampedLock的特点
- StampedLock 是从 JDK1.8 开始提供,它的性能比 ReadWriteLock 好
- StampedLock 支持:乐观读锁、悲观读锁、写锁
- StampedLock 不支持重入
- StampedLock 支持锁的降级和升级 (即乐观读锁升级为写锁)
StampedLock 无论写锁还是读锁,都不支持Conditon等待
StampedLock使用示例
@Slf4j(topic = "c.DataContainerStamped")
public class DataContainerStamped {
private int data;
private final StampedLock lock = new StampedLock();
public DataContainerStamped(int data) {
this.data = data;
}
public void read(int readTime) throws InterruptedException {
long stamp = lock.tryOptimisticRead();
log.debug("optimistic read locking...{}", stamp);
Thread.sleep(readTime * 1000L);
//validate方法用于验戳,即验证数据是否被修改
if (lock.validate(stamp)) {
log.debug("read finish...{}, data:{}", stamp, data);
return;
}
// 锁升级 - 读锁(悲观读锁)
log.debug("updating to read lock... {}", stamp);
try {
stamp = lock.readLock();
log.debug("read lock {}", stamp);
Thread.sleep(readTime * 1000L);
log.debug("read finish...{}, data:{}", stamp, data);
} finally {
log.debug("read unlock {}", stamp);
lock.unlockRead(stamp);
}
}
public void write(int newData) throws InterruptedException {
long stamp = lock.writeLock();
log.debug("write lock {}", stamp);
try {
Thread.sleep(2 * 1000L);
this.data = newData;
} finally {
log.debug("write unlock {}", stamp);
lock.unlockWrite(stamp);
}
}
}
测试代码:
public static void main(String[] args) throws InterruptedException {
DataContainerStamped dataContainer = new DataContainerStamped(1);
new Thread(() -> {
try {
dataContainer.read(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "t1").start();
new Thread(() -> {
try {
dataContainer.write(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "t2").start();
}
测试结果:
可以看到在“01:28:24”,t1获取乐观读锁,随后t2获取写锁,t2并没有被阻塞,因此验证了可以从乐观读锁升级为写锁的特点。StampedLock 相比于读写锁有很多优点,但是有两个比较大的缺点:- StampedLock 不支持条件变量
- StampedLock 不支持可重入