最近博主看了好多订阅的技术公众号,尤其是业内大佬的文章,写的非常不错,通熟易懂。突然就萌生了一个想法,为啥不自己也经营一个呢?通过写文章的好处还是很多的,写的过程其实也是载总结梳理知识体系的过程,能够将自己所学的技术都沉淀下来。想写一篇好的博文也不少那么容易的,需要花费很多精力和时间,查阅很多资料书籍的,能学到很多东西,查漏补缺。关注的人数多了,无形之中也提高自己在业内的影响力,在面试中和工作中也是一个加分项。
所以打算持续写下去,将所学的东西分享出来,工作之余会尽最大努力及时更新。近期打算就面试中的提问非常多的Java并发编程写一些心得,如果有什么错误的地方还请大家指正。
关于并发编程这块,先分享juc并发包相关的内容,系列目录如下:
-
(第2节)Java并发编程之Lock灵魂-AQS同步器原理(上)(未发布)
-
(第3节)Java并发编程之Lock灵魂-AQS同步器原理(下)(未发布)
-
(第4节)Java并发编程之重入锁ReentrantLock(未发布)
-
(第5节)Java并发编程之读写锁ReentrantReadWriteLock(未发布)
-
(第6节)Java并发编程之线程通信-Condition接口(未发布)
Lock接口的诞生
java并发包JUC中Lock接口是很多锁(重入锁、读写锁、分段锁等待)的老祖宗,它提供了锁的规范和标准。在java Lock接口出现之前,在多线程之间同步访问共享资源,都是依赖synchronized关键字实现锁功能的,在Java SE 1.5之后,并发包中新增 了Lock接口以及相关实现类用来实现锁功能,它提供了与synchronized关键字类似的同步功能,但是在使用时需要显式地获取和释放锁(synchronized同步块或者方法所提供的属于隐式获取和释放锁,由JVM控制,不需要程序员写代码来控制加锁和释放锁)。虽然缺少了隐式获取释放锁的便捷性,但是却拥有了锁获取与释放的可操作性、可中断的获取锁以及超时获取锁等多种synchronized关键字所不具备的同步特性。
Lock实现锁与synchronized锁对比
虽然synchronized关键字会隐式地获取锁和释放锁,但同时它将锁的获取和释放固化了,也就是先获取再释放。这种方式简化了同步的管理,可是扩展性没有显示的锁获取和释放来的好。例如,针对一个交叉获取和释放锁的场景,手把手进行锁获取和释放,先获得锁A,然后再获取锁B,当锁B获得后,释放锁A同时获取锁C,当锁C获得后,再释放B同时获取锁D,以此类推。这种场景下,synchronized关键字就不那么容易实现了,而使用Lock却容易许多。
Lock接口类结构图
Lock接口的特性
Lock接口提供的synchronized关键字所不具备的主要特性如表所示:
特性 | 描述 |
---|---|
尝试非阻塞地获取锁 | 当前线程尝试获取锁,如果这一时刻锁没有被其他线程获取到,则获得锁成功并持有锁 |
能被中断地获取锁 | 与synchronized不同,获得锁的线程能够响应中断,当获得锁的线程被中断时,抛出中断异常,同时锁会被释放 |
超时获取锁 | 在指定的截止时间之前获得锁,如果超出截止时间让然无法或多,则从当前返回 |
Lock接口主要API
方法名称 | 描述 |
---|---|
void lock() | 当前线程调用该方法去获取锁,获得锁成功之后,从该方法返回。获得锁失败添加到同步队列,线程阻塞。 |
void lockInterruptibly() throws InterruptedException; | 可以中断的获取锁,与lock方法不同之处在于可以响应中断,在获得锁的过程中可以中断当前线程,抛出中断异常。 |
boolean tryLock(); | 尝试非阻塞的方式获取锁,调用该方法后立刻返回,获得锁成功则返回true,反之返回false。 |
boolean tryLock(long time, TimeUnit unit) throws InterruptedException; | 超时获取锁,当前线程在一下三种情况下会返回: ①当前线程在超时时间内获得了锁 ②当前线程在超时时间内被中断 ③超时时间结束 |
void unlock(); | 释放锁 |
Condition newCondition(); | 获取等待通知组件,该组件和当前的锁绑定,当前线程只有获得了锁,才能调用该组件的wait方法,但是调用该方法,当前线程将会加入到等待队列,同时会释放锁 |
这里先简单介绍一下Lock接口的API,随后的章节会详细介绍同步器 AbstractQueuedSynchronizer以及常用Lock接口的实现ReentrantLock。Lock接口的实现基本都是通过聚合了一个同步器的子类来完成线程访问控制的。
队列同步器AbstractQueuedSynchronizer(以下简称同步器),是用来构建锁或者其他同步组 件的基础框架,它使用了一个int成员变量表示同步状态,通过内置的FIFO队列来完成资源获 取线程的排队工作,并发包的作者(Doug Lea)期望它能够成为实现大部分同步需求的基础,下一节会具体讲解。
参考:《并发编程的艺术》,非常好的一本书