| 好看请赞,养成习惯
你有一个思想,我有一个思想,我们交换后,一个人就有两个思想
If you can NOT explain it simply, you do NOT understand it well enough
现陆续将Demo代码和技术文章整理在一起 Github实践精选 ,方便大家阅读查看,本文同样收录在此,觉得不错,还请Star
写在前面进入源码阶段了,写了十几篇的 并发系列 知识铺垫终于要派上用场了。相信很多人已经忘了其中的一些理论知识,别担心,我会在源码环节带入相应的理论知识点帮助大家回忆,做到理论与实践相结合,另外这是超长图文,建议收藏,如果对你有用还请点赞让更多人看到
Java SDK 为什么要设计 Lock曾几何时幻想过,如果 Java 并发控制只有 synchronized 多好,只有下面三种使用方式,简单方便
public class ThreeSync { private static final Object object = new Object(); public synchronized void normalSyncMethod(){ //临界区 } public static synchronized void staticSyncMethod(){ //临界区 } public void syncBlockMethod(){ synchronized (object){ //临界区 } } }如果在 Java 1.5之前,确实是这样,自从 1.5 版本 Doug Lea 大师就重新造了一个轮子 Lock
我们常说:“避免重复造轮子”,如果有了轮子还是要坚持再造个轮子,那么肯定传统的轮子在某些应用场景中不能很好的解决问题
不知你是否还记得 ,其中【不可剥夺条件】是指:
线程已经获得资源,在未使用完之前,不能被剥夺,只能在使用完时自己释放
要想破坏这个条件,就需要具有申请不到进一步资源就释放已有资源的能力
很显然,这个能力是 synchronized 不具备的,使用 synchronized ,如果线程申请不到资源就会进入阻塞状态,我们做什么也改变不了它的状态,这是 synchronized 轮子的致命弱点,这就强有力的给了重造轮子 Lock 的理由
显式锁 Lock旧轮子有弱点,新轮子就要解决这些问题,所以要具备不会阻塞的功能,下面的三个方案都是解决这个问题的好办法(看下面表格描述你就明白三个方案的含义了)
特性 描述 API能响应中断 如果不能自己释放,那可以响应中断也是很好的。Java多线程中断机制 专门描述了中断过程,目的是通过中断信号来跳出某种状态,比如阻塞 lockInterruptbly()
非阻塞式的获取锁 尝试获取,获取不到不会阻塞,直接返回 tryLock()
支持超时 给定一个时间限制,如果一段时间内没获取到,不是进入阻塞状态,同样直接返回 tryLock(long time, timeUnit)
好的方案有了,但鱼和熊掌不可兼得,Lock 多了 synchronized 不具备的特性,自然不会像 synchronized 那样一个关键字三个玩法走遍全天下,在使用上也相对复杂了一丢丢
Lock 使用范式synchronized 有标准用法,这样的优良传统咱 Lock 也得有,相信很多人都知道使用 Lock 的一个范式
Lock lock = new ReentrantLock(); lock.lock(); try{ ... }finally{ lock.unlock(); }既然是范式(没事不要挑战更改写法的那种),肯定有其理由,我们来看一下
标准1—finally 中释放锁这个大家应该都会明白,在 finally 中释放锁,目的是保证在获取到锁之后,最终能被释放
标准2—在 try{} 外面获取锁不知道你有没有想过,为什么会有标准 2 的存在,我们通常是“喜欢” try 住所有内容,生怕发生异常不能捕获的
在 try{} 外获取锁主要考虑两个方面:
如果没有获取到锁就抛出异常,最终释放锁肯定是有问题的,因为还未曾拥有锁谈何释放锁呢
如果在获取锁时抛出了异常,也就是当前线程并未获取到锁,但执行到 finally 代码时,如果恰巧别的线程获取到了锁,则会被释放掉(无故释放)
不同锁的实现方式略有不同,范式的存在就是要避免一切问题的出现,所以大家尽量遵守范式