Java多线程开发中,如果涉及到共享资源操作场景,那就必不可少要和Java锁打交道。
Java中的锁机制主要分为 Lock
和 Synchronized
,本文主要分析Java 锁机制的使用和实现原理,按照Java锁使用、JDK中锁实现、系统层锁实现的顺序来进行分析,话不多说,let's go~
Java锁使用
在Lock接口出现之前,Java程序是靠 synchronized
关键字实现锁功能的,而 Java SE 5之后,并发包中新增了 Lock
接口(以及相关实现类)用来实现锁功能,它提供了与synchronized关键字类似的同步功能,只是在使用时需要显式地获取和释放锁。虽然它缺少了(通过 synchronized
块或者方法)隐式获取释放锁的便捷性,但是却拥有了锁获取与释放的可操作性、可中断的获取锁以及超时获取锁等多种synchronized
关键字所不具备的同步特性。
Java锁使用示例:
Lock lock = new ReentrantLock();
lock.lock();
try {
// ..
} finally {
lock.unlock();
}
注意:在finally
块中释放锁,目的是保证在获取到锁之后,最终能够被释放。不要将获取锁的过程写在 try
块中,因为如果在获取锁(自定义锁的实现)时发生了异常,异常抛出的同时,会提前进行unlock导致IllegalMonitorStateException
异常。
Lock
相较于 Synchronized
优势如下:
-
可中断获取锁:使用
synchronized
关键字获取锁的时候,如果线程没有获取到被阻塞了,那么这个时候该线程是不响应中断(interrupt)的,而使用Lock.lockInterruptibly()
获取锁时被中断,线程将抛出中断异常。 -
可非阻塞获取锁:使用
synchronized
关键字获取锁时,如果没有成功获取,只有被阻塞,而使用Lock.tryLock()
获取锁时,如果没有获取成功也不会阻塞而是直接返回false。 -
可限定获取锁的超时时间:使用
Lock.tryLock(long time, TimeUnit unit)
。 - 同一个所对象上可以有多个等待队列(
Conditin
,类似于Object.wait()
,支持公平锁模式)。