ReentrantLock、ReentrantReadWriteLock、StampedLock
一、大厂面试题
二、请你简单聊聊ReentrantReadWriteLock 读写锁
1.是什么
①:读写锁说明
②:演变
③:【读写锁】意义和特点
2.特点
ReentrantReadWriteLock锁降级
降级
锁降级是为了让当前线程感知到数据的变化,目的是为了保证数据的可见性
不可锁升级
写锁和读锁是互斥的
读写锁之读写规矩,解释为什么要锁降级?
三、邮戳锁StampedLock
1.是什么
2.它是由锁饥饿问题引出
①:锁饥饿问题
②:如何缓解锁饥饿问题
③:StampedLock类的乐观读锁闪亮登场
3.StampedLock的特点
4. 乐观读模式
读的时候不允许获取写锁的介入
public class StampedLockDemo {
static int number = 37;
static StampedLock stampedLock = new StampedLock();
public void write() {
long stamp = stampedLock.writeLock();
System.out.println(Thread.currentThread().getName() + " 写线程准备修改");
try {
number = number + 13;
} finally {
stampedLock.unlockWrite(stamp);
}
System.out.println(Thread.currentThread().getName() + " 写线程结束修改");
}
//悲观读,读没有完成时候写锁无法获得锁
public void read() {
long stamp = stampedLock.readLock();
System.out.println(Thread.currentThread().getName() + " come in readLock code lock,4 seconds continue ...");
//暂停4秒钟
for (int i = 0; i < 4; i++) {
try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
System.out.println(Thread.currentThread().getName() + " 正在读取中 ...");
}
try {
int result = number;
System.out.println(Thread.currentThread().getName() + " 获得成员变量值result=" + result);
System.out.println("写线程没有修改成功,读锁时候写锁无法介入,传统的读写互斥");
} finally {
stampedLock.unlockRead(stamp);
}
}
public static void main(String[] args) {
StampedLockDemo resource = new StampedLockDemo();
new Thread(() -> {
resource.read();
}, "readThread").start();
//暂停几秒钟线程
try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + " . . .come in");
resource.write();
}, "writeThread").start();
//暂停几秒钟线程
try { TimeUnit.SECONDS.sleep(4); } catch (InterruptedException e) { e.printStackTrace(); }
System.out.println(Thread.currentThread().getName() + " number:" + number);
}
}
readThread come in readLock code lock,4 seconds continue ...
readThread 正在读取中 ...
writeThread . . .come in
readThread 正在读取中 ...
readThread 正在读取中 ...
readThread 正在读取中 ...
readThread 获得成员变量值result=37
写线程没有修改成功,读锁时候写锁无法介入,传统的读写互斥
writeThread 写线程准备修改
writeThread 写线程结束修改
main number:50
public class StampedLockDemo {
static int number = 37;
static StampedLock stampedLock = new StampedLock();
public static void main(String[] args) {
StampedLockDemo resource = new StampedLockDemo();
new Thread(() -> {
resource.tryOptimisticRead();
}, "readThread").start();
//暂停2秒钟线程,读过程中可以写介入 演示
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + " . . .come in");
resource.write();
}, "writeThread").start();
}
public void write() {
long stamp = stampedLock.writeLock();
System.out.println(Thread.currentThread().getName() + " 写线程准备修改");
try {
number = number + 13;
} finally {
stampedLock.unlockWrite(stamp);
}
System.out.println(Thread.currentThread().getName() + " 写线程结束修改");
}
//悲观读,读没有完成时候写锁无法获得锁
public void read() {
long stamp = stampedLock.readLock();
System.out.println(Thread.currentThread().getName() + " come in readLock code lock,4 seconds continue ...");
//暂停4秒钟
for (int i = 0; i < 4; i++) {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 正在读取中 ...");
}
try {
int result = number;
System.out.println(Thread.currentThread().getName() + " 获得成员变量值result=" + result);
System.out.println("写线程没有修改成功,读锁时候写锁无法介入,传统的读写互斥");
} finally {
stampedLock.unlockRead(stamp);
}
}
//乐观读,读的过程中也允许写锁介入
public void tryOptimisticRead() {
long stamp = stampedLock.tryOptimisticRead();
int result = number;
//故意间隔4秒钟,很乐观认为读取中没有其它线程修改过number值,具体靠判断
System.out.println("4秒前stampedLock.validate方法值(true无修改,false有修改) " + stampedLock.validate(stamp));
for (int i = 0; i < 4; i++) {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " 正在读取..." + i + "秒后stampedLock.validate方法值(true无修改,false有修改) " + stampedLock.validate(stamp));
}
if (!stampedLock.validate(stamp)) {
System.out.println("有人修改过---有写操作");
stamp = stampedLock.readLock();
try {
System.out.println("从乐观读 升级为 悲观读");
result = number;
System.out.println("重新悲观读后result:" + result);
} finally {
stampedLock.unlockRead(stamp);
}
}
System.out.println(Thread.currentThread().getName() + " finally value:" + result);
}
}
4秒前stampedLock.validate方法值(true无修改,false有修改) true
readThread 正在读取...0秒后stampedLock.validate方法值(true无修改,false有修改) true
readThread 正在读取...1秒后stampedLock.validate方法值(true无修改,false有修改) true
writeThread . . .come in
writeThread 写线程准备修改
writeThread 写线程结束修改
readThread 正在读取...2秒后stampedLock.validate方法值(true无修改,false有修改) false
readThread 正在读取...3秒后stampedLock.validate方法值(true无修改,false有修改) false
有人修改过---有写操作
从乐观读 升级为 悲观读
重新悲观读后result:50
readThread finally value:50