Lock 接口和类

Java 原生的锁-基于对象的锁,一般配合 synchronized 关键字使用。 Java 在 java.util.concurrent.locks 包下,提供了几个关于锁的接口和类,他们有更强大的功能和性能

synchronized 的不足

  • 临界区是只读操作,可以多线程一起执行,synchronized 只能有一个线程执行
  • synchronized 无法直到当前线程有没有成功获取到锁
  • 使用 synchronized, 如果临界区因为 IO 或者 sleep等阻塞了,当前线程又未释放锁,会导致所有线程等待。

这些问题都是locks包下的锁可以解决的

锁的分类

是否可重入

重入锁,就是说支持一个线程对资源重复加锁

synchronized 使用的重入锁,就是 synchronized实例方法里可以调用另一个本实例的synchronized实例方法。

ReentrantLock 也是重入锁,是本文介绍的重点类。

是否公平

公平,就是FIFO,是否是先来后到的顺序来获取锁。

非公平锁是一种抢占机制,随机获得锁。

一般情况下,非公平锁会提升一定的效率

非公平说可能会发生线程饥饿。

读写锁和排他锁

synchronized用的锁和ReentrantLock 都是排他锁,即这些锁只能有一个线程访问。

读写锁可以运行多个线程同时访问。Java提供了 ReentrantReadWriteLock 作为读写锁的默认实现,内部维护了两个锁:读锁和写锁。

读写锁,在写线程访问时,所有的读线程和其它写线程均被阻塞。

JDK 有关锁的接口

抽象类 AQS/AQLS/AOS

AQS 是抽象队列同步器,资源使用 int类型的 state 来表示, AQLS (AbstractQueuedLongSynchronizer)代码和AQS 几乎一样,资源类型变成了 long

AQS 和 AQLS 继承了 AOS(AbstractOwnableSynchronizer).这个类用来表示锁和持有者的关系(独占模式)

// 独占模式,锁的持有者  
private transient Thread exclusiveOwnerThread;  

// 设置锁持有者  
protected final void setExclusiveOwnerThread(Thread t) {  
    exclusiveOwnerThread = t;  
}  

// 获取锁的持有线程  
protected final Thread getExclusiveOwnerThread() {  
    return exclusiveOwnerThread;  
}  

接口 Condition/Lock/ReadWriteLock

Lock 里有释放和获取锁的方法声明,Lock 可以获得 Condition

Condition newCondition();

ReadWriteLock 里有两个方法, 分别返回 读锁写锁

public interface ReadWriteLock {  
    /**  
     * Returns the lock used for reading.     *     * @return the lock used for reading  
     */ 
        Lock readLock();  
  
    /**  
     * Returns the lock used for writing.     *     * @return the lock used for writing  
     */  
       Lock writeLock();  
}

对象锁是继承Objectwait/notify方法实现 等待/通知 机制。Condition接口提供了类似的方法,通过Lock来实现 通知/等待 机制。 我们来做一下总结

项目对象锁Condition
前置条件synchronized 获取对象锁通过Lock.lock 获取锁,调用Lock.newCondition 获取 Condition 对象
调用方式object.wait/notify()condition.await/signal()
等待队列个数1个多个
释放锁进入 等待/超时等待 模式支持支持
释放锁进入等待,状态不中断不支持支持
唤醒队列中一个/全部线程支持支持

Condition 和 Object 的 wait / notify 类似。

Condition 中的 await 对用 Object 的wait,signal/signal 对应 Object 的 notify/notifyuAll().

ReentrantLock

JDK 中 Lock 的默认实现,实现了锁的基本功能。内部有一个抽象类 SyncSync继承了 AQS

ReentrantLock内部有两个非抽象类NonfairSyncFairSync,它们都继承了Sync。这意味着 ReentrantLock 可以支持公平锁和非公平锁。

在ReentrantLock的构造方法里,可以传入一个boolean类型的参数,来指定它是否是一个公平锁,默认情况下是非公平的。这个参数一旦实例化后就不能修改,只能通过isFair()方法来查看。

ReentrantReadWriteLock

JDK 中 ReadWriteLock 的默认实现,与ReentrantLock 类似,可重入,支持公平锁和非公平锁,不同的时,它支持读写锁

AbstractOwnableSynchronizer
AbstractQueuedLongSynchronizer
AbstractQueuedSynchronizer
«Interface»
Condition
«Interface»
Lock
LockSupport
«Interface»
ReadWriteLock
ReentrantLock
ReentrantReadWriteLock
StampedLock
Last Updated:
Contributors: himcs