锁是用来控制多个线程访问共享资源的方式,一般来说,一个锁能够防止多个线程同时访问共享资源,在 Lock 接口出现之前,Java 应用程序只能依靠 synchronized 关键字来实现同步锁的功能,在 Java 5 以后,增加了 JUC 的并发包且提供了 Lock 接口用来实现锁的功能,它提供了与 synchroinzed 关键字类似的同步功能,只是它比 synchronized 更灵活,能够显示的获取和释放锁。
Lock 实现类
Lock 是一个接口,有两个核心方法 lock() 和 unlock(),它有很多实现类,这里介绍两个常用的实现类的使用,ReentrantLock 和 ReentrantReadWriteLock。
Lock 和 ReentrantLock 的类图如下所示。

AbstractQueuedSynchronizer 同步器是实现 Lock 锁机制的核心,后面会详细讲解
Sync、NonfairSync、FairSync 是 ReentrantLock 的内部类,继承了 AbstractQueuedSynchronizer 类
接下来介绍 ReentrantLock 和 ReentrantReadWriteLock 的基本使用
Lock 使用
ReentrantLock
重入锁,表示支持重新进入的锁,也就是说,如果当前线程 t1 通过调用 lock 方法获取了锁之后,再次调用 lock,是不会再阻塞去获取锁的,直接增加重试次数就行了。
public class AtomicDemo {private static int count;private static Lock lock = new ReentrantLock();public static void main(String[] args) {for (int i = 0; i < 1000; i++) {new Thread(new Runner()).start();}try {Thread.sleep(4000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("运行结果:" + count);}private static class Runner implements Runnable {@Overridepublic void run() {// 获取锁lock.lock();try {Thread.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}count++;// 释放锁lock.unlock();}}}
ReentrantReadWriteLock
可重入读写锁,表示支持重新进入的锁,并且读写锁维护了一对锁,读锁和写锁,具有如下特征。
- 读锁与读锁可以共享
- 读锁与写锁不可以共享(排他)
- 写锁与写锁不可以共享(排他)
适用于读多写少的场景,在该场景下读写锁能够提供比排它锁更好的并发性和吞吐量。
在执行写操作是,线程必须要获取写锁,当已经有线程持有写锁的情况下,当前线程会被阻塞,只有当写锁释放以后,读写操作才能继续执行。使用读写锁提升读操作的并发性,也保证每次写操作对所有的读写操作的可见性。
public class ReadWriteLockDemo {private static Map<String, Object> cacheMap = new HashMap<>();private static ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();private static Lock readLock = readWriteLock.readLock();private static Lock writeLock = readWriteLock.writeLock();/*** 获取缓存数据** @param key* @return*/public static Object get(String key) {readLock.lock();try {return cacheMap.get(key);} finally {readLock.unlock();}}/*** 保存缓存数据** @param key* @param value* @return*/public static Object put(String key, Object value) {writeLock.lock();try {return cacheMap.put(key, value);} finally {writeLock.unlock();}}}
synchronized 和 Lock 的区别
- 从层次上,一个是关键字、一个是类,这个是最直观的的差异
- 从使用上,Lock 具备更大的灵活性,可以控制锁的获取和释放,而 synchronized 锁的释放是被动的,当出现异常或者同步代码块执行完成后才会释放锁
- Lock 可以判断锁的状态,而 synchronized 不可以
- Lock 可以实现公平锁、非公平锁,而 synchronized 只有非公平锁
作者:殷建卫 链接:https://www.yuque.com/yinjianwei/vyrvkf/gsq47i 来源:殷建卫 - 架构笔记 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
