- 它主要解决的是读写线程比例相差太大,例如共有100个线程
- 对这个锁进行加锁,比例为99个读线程,1个线程;那么
- 就会出现写线程总是抢不到锁的情况,这种情况称为:线程“饥饿”
- 为了避免这种情况,提高效率,那么就出现了这个StampedLock
- 注意:
2.1、StampedLock不是一个重入锁
2.2、StampedLock不支持Condition
所有获取锁的方法,都返回一个邮戳(Stamp),Stamp为0表示获取失败,其余都表示成功;
所有释放锁的方法,都需要一个邮戳(Stamp),这个Stamp必须是和成功获取锁时得到的Stamp一致;
StampedLock是不可重入的;(如果一个线程已经持有了写锁,再去获取写锁的话就会造成死锁)
代码
public class StampedLockTest02 {
private static List<Integer> shareDataList = Arrays.asList(1,2,3,4);
private static StampedLock lock = new StampedLock();
/**
* 读方法
*/
private static void read(){
//尝试获取读锁
long stamp = lock.tryOptimisticRead();
//如果stamp没有被修改
if(lock.validate(stamp)){
try {
//执行加锁
stamp = lock.readLock();
//假设读取操作需要耗时1秒钟
Thread.sleep(1_000);
System.out.println(Thread.currentThread().getName()
+"读到的数据是:"+shareDataList);
} catch (Exception e) {
e.printStackTrace();
}finally{
lock.unlockRead(stamp);
}
}
}
/**
* 写方法
*/
private static void write(){
long stamp = -1;
stamp = lock.writeLock();
try {
//假设写操作需要耗时1秒钟
Thread.sleep(1_000);
String threadName = Thread.currentThread().getName();
System.out.println(threadName+"抢到了锁,开始进行写操作……");
//将List中的每一个元素进行+1操作
shareDataList = shareDataList.stream()
.map(intNum -> ++intNum)
.collect(Collectors.toList());
System.out.println(threadName+"写操作完毕!");
} catch (Exception e) {
e.printStackTrace();
}finally{
lock.unlockWrite(stamp);
}
}
public static void main(String[] args) {
//创建9个读线程和1个写线程一直去操作shareDataList的数据
IntStream.rangeClosed(1, 100).forEach(i ->{
if(i==100){
new Thread("写线程:"){
@Override
public void run() {
for(;;){
write();
}
}
}.start();
return;
}
new Thread("读线程"+i+":"){
@Override
public void run() {
while(true){
read();
}
}
}.start();
});
}
}
显示结果