Lock和Condition 2021-07-22

Lock与Condition
Lock

为什么java有了语言层面的synchronized,还在SDK中提供了Lock这种互斥锁呢?

synchronzied 有可能会 产生死锁,而Lock 是可以中断的锁,可以破坏死锁中“占用且不可抢占的条件”。

Lock支持响应中断、支持超时,并且支持非阻塞地获取锁,完美解决了“不可抢占”的问题。

Lock提供的API,

//支持中断
lockInterruptibly() throws InterruptedException             

//支持超时    
tryLock(long time, TimeUnit unit) throws InterruptedException 

//非阻塞获取锁    
boolean tryLock();    

Lock是如何保证可见性的?

lock()和unLock()底层会读写一个volatile的state变量,根据Lock经典的编程范式来看

lock.lock();try//共享变量操作 
   ...               ②
}finally {
	lock.unLock();}

根据happens-Before 顺序性规则、volatile变量规则和传递性规则,

② happens-Before 于 ③,而 ③ happens-Before 于 ①, 那么 ② happens-Before 于 ①

所以,首先获取lock锁的线程对于共享变量的操作,对后获取lock锁的线程是可见的,因此Lock保证了可见性

我们一般使用ReentrantLock实现Lock ,
Lock lock = new ReentrantLock();
ReentrantLock是可重入锁,且支持公平锁和非公平锁,默认为非公平锁

锁能够解决并发问题,也会带来性能问题和死锁问题,Doug Lea在《Java并发编程:设计原则与模式》中,推荐三个用锁的最佳实践如下,

  1. 永远只在更新对象的成员变量时加锁
  2. 永远只在访问可变的成员变量时加锁
  3. 永远不在调用其他对象的方法时加锁

另外还有业界广为人知的规则,减少锁的粒度和减少锁持有的时间

Condition

Condition实现了管程模型里面的条件变量,synchronized实现的管程中只能有一个条件变量,而Lock + Condition实现的管程中支持多个条件变量。

  1. Condition通过Lock#newConditon()获取
  2. await() 阻塞线程,signal()和signalAll()唤醒线程

巧了,Lock + Condition 提供await()、signal()和signalAll()实现的功能,和synchronized中使用的wait()、notity()和notityAll() 是一致的,均实现了线程的通知-机制。

BlockQueue系列便是借助Condition来实现的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值