锁12—锁升级(锁膨胀)、锁降级
************ 如有侵权请提示删除 ***************
锁升级:偏向锁、轻量级锁、重量级锁的过渡。
(https://blog.youkuaiyun.com/haoranhaoshi/article/details/92388612)
优先尝试低级锁,不能适用,就升级锁。线程获取到不被其他线程获取的监视类或对象,监视类或对象头部记录线程ID,线程退出对监视类或对象的获取时直接退出,是偏向锁。
如果有其他线程来获取监视类或对象,发现头部记录的线程ID不是自己的ID(https://blog.youkuaiyun.com/haoranhaoshi/article/details/108501633),
就升级为轻量级锁。轻量级锁采用CAS机制(https://blog.youkuaiyun.com/haoranhaoshi/article/details/108507092),
尝试一定次数(默认10)获取不到监视类或对象,则升级为重量级锁(一旦获取不到监视类或对象就阻塞。
(https://blog.youkuaiyun.com/haoranhaoshi/article/details/108461058)
因为操作唤醒阻塞的线程需从用户态切换到内存态,开销大,所以才优先使用轻量级锁进行循环判断是否可获取监视类或对象。
锁降级:写锁降级成为读锁。持有写锁的同时,获取到读锁,然后释放写锁。避免读到被其他线程修改的数据。
oracle官网锁降级示例:
/**
* @Description 锁降级
*/
public class CachedData {
Object data;
//volatile修饰,保持内存可见性
volatile boolean cacheValid;
//可重入读写锁
final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
void processCachedData() {
//首先获取读锁
rwl.readLock().lock();
//发现没有缓存数据则放弃读锁,获取写锁
if (!cacheValid) {
// 在获取写锁之前必须释放读锁
rwl.readLock().unlock();
rwl.writeLock().lock();
try {
// 重新检查状态,因为另一个线程可能有
// 在执行操作之前获取了写锁定并更改了状态。
if (!cacheValid) {
data = new Object();//数据赋值
cacheValid = true;
}
// 通过在释放写锁之前获取读锁来降级
rwl.readLock().lock();
} finally {
//进行锁降级
rwl.writeLock().unlock();
// 解锁写入,仍保持读取状态
}
}
try {
//使用数据
//use(data);
} finally {
rwl.readLock().unlock();
}
}
}