JDK中为什么有了Synchronized还有Lock接口呢?
当回答这个问题的时候,有人会说是因为性能的原因。但你应该知道,自从JDK1.6以后,对synchronized进行了优化之后,synchronized又开始被推荐使用了,何况性能问题通过优化大多都是可以解决的,所以性能并不是Lock
接口出现的原因。
那why?
因为synchronized具有它的局限性。synchronized在申请资源的时候,如果申请不到,线程直接就进入阻塞状态了,而线程进入阻塞状态,啥也干不了,也释放不了线程已经占有的资源。即它不可被抢占。
这是我们不愿看到的,那如果我们现在重新设计一把锁去解决这个问题,那该如何去设计?
⤵️ 以下是三种方案:
-
能够响应中断。synchronized 的问题是,持有锁 A 后,如果尝试获取锁 B 失败,那么线程就 进入阻塞状态,一旦发生死锁,就没有任何机会来唤醒阻塞的线程。但如果阻塞状态的线程能 够响应中断信号,也就是说当我们给阻塞的线程发送中断信号的时候,能够唤醒它,那它就有 机会释放曾经持有的锁 A。这样就破坏了不可抢占条件了。
-
支持超时。如果线程在一段时间之内没有获取到锁,不是进入阻塞状态,而是返回一个错误, 那这个线程也有机会释放曾经持有的锁。这样也能破坏不可抢占条件。
-
非阻塞地获取锁。如果尝试获取锁失败,并不进入阻塞状态,而是直接返回,那这个线程也有 机会释放曾经持有的锁。这样也能破坏不可抢占条件。
这三种方案可以全面弥补 synchronized 的问题。到这里相信你应该也能理解了,这三个方案就 是“重复造轮子”的主要原因,体现在 API 上,就是 Lock 接口的三个方法。详情如下: