锁框架 - litter-fish/ReadSource GitHub Wiki

根据锁添加到Java中的时间,Java中的锁可以分为同步锁和JUC包中的锁。

  • 同步锁:即通过synchronized关键字来进行同步,实现对竞争资源的互斥访问的锁。Java 1.0版本中就已经支持同步锁了。同步锁的原理是,对于每一个对象有且仅有一个同步锁;不同的线程能共同访问该同步锁。但是在同一个时间点该同步锁能且只能被一个线程获取到。获取到同步锁的线程就能进行CPU调度,从而在CPU上执行;而没有获取到同步锁的线程必须进行等待,直到获取到同步锁之后才能继续运行。这即是多线程通过同步锁进行同步的原理。
  • JUC包中的锁:相比同步锁,JUC包中的锁的功能更加强大,它为锁提供了一个框架,该框架允许更灵活地使用锁,只是它的用法更难罢了。JUC包中的锁包括:Lock接口,ReadWriteLock接口,LockSupport阻塞原语,Condition条件,AbstractOwnableSynchronizer / AbstractQueuedSynchronizer / AbstractQueuedLongSynchronizer三个抽象类,ReentrantLock重入锁,ReentrantReadWriteLock读写锁。由于CountDownLatch,CyclicBarrier和Semaphore也是通过AQS来实现的;

锁的框架图 8301255c7acc24953d37827053b3d242.jpeg

Lock接口 JUC包中的Lock接口支持那些语义不同(重入、公平等)的锁规则。所谓语义不同,是指锁可是有公平机制的锁、非公平机制的锁、可重入的锁等等。公平机制是指不同线程获取锁的机制是公平的,而非公平机制则是指不同线程获取锁的机制是非公平的,可重入的锁是指同一个锁能够被一个线程多次获取。 Lock接口有以下重要的方法:

public interface Lock {
    // 获取锁,如果不能获取,那么当前线程将不能被线程调度处理(即阻塞),直到获取到锁
    void lock();
    // 获取锁,可被中断
    void lockInterruptibly() throws InterruptedException;
    // 尝试获取锁
    boolean tryLock();
    // 尝试获取锁,time为超时时间,第二个参数为第一个参数的单位
    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
    // 释放锁
    void unlock();
    // 获取当前锁实例的状态
    Condition newCondition();
}

ReentrantLock ReentrantLock是独占锁。所谓独占锁,是指只能被独自占领,即同一个时间点只能被一个线程锁获取到的锁。ReentrantLock锁包括公平的ReentrantLock和非公平的ReentrantLock。公平的ReentrantLock是指不同线程获取锁的机制是公平的,而非公平的ReentrantLock则是指不同线程获取锁的机制是非公平的,ReentrantLock是可重入的锁。 ReentrantLock的UML类图如下: 98cba9f0715955d06f702dd098eab906.jpeg

  • ReentrantLock实现了Lock接口。ReentrantLock中有一个成员变量sync,sync是Sync类型;
  • Sync是一个抽象类,而且它继承于AQS。
  • ReentrantLock中有公平锁类FairSync和非公平锁类NonfairSync,它们都是Sync的子类。ReentrantReadWriteLock中sync对象,是FairSync与NonfairSync中的一种,这也意味着ReentrantLock是公平锁或非公平锁中的一种,ReentrantLock默认是非公平锁。

ReentrantReadWriteLock ReentrantReadWriteLock是读写锁接口ReadWriteLock的实现类,它包括子类ReadLock和WriteLock。ReadLock是共享锁,而WriteLock是独占锁。 ReentrantReadWriteLock的UML类图如下: f76312bee64f5b7b4d82dc74a9c30a4e.jpeg

  • ReentrantReadWriteLock实现了ReadWriteLock接口。
  • ReentrantReadWriteLock中包含sync对象,读锁readLock和写锁writeLock。
  • 读锁ReadLock和写锁WriteLock都实现了Lock接口。和ReentrantLock一样,sync是Sync类型;而且,Sync也是一个继承于AQS的抽象类。Sync也包括公平锁FairSync和非公平锁NonfairSync。

Condition Condition需要和Lock联合使用,它的作用是代替Object监视器方法,可以通过await()、signal()来休眠或唤醒线程。Condition接口描述了可能会与锁有关联的条件变量。这些变量在用法上与使用Object.wait()访问的隐式监视器类似,但提供了更强大的功能。需要特别指出的是,单个Lock可能与多个Condition对象关联。为了避免兼容性问题,Condition方法的名称与对应的Object版本中的不同。

LockSupport LockSupport提供创建锁和其他同步类的基本线程阻塞原语。LockSupport的功能和Thread中的Thread.suspend()和Thread.resume()有点类似,LockSupport中的park()和unpark()的作用分别是阻塞线程和解除阻塞线程。但是park()和unpark()不会遇到Thread.suspend和Thread.resume所可能引发的死锁问题。

CountDownLatch CountDownLatch是一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。 CountDownLatch的UML类图如下: 787980eb84bc00205d4cef101b15ee4c.jpeg CountDownLatch包含了sync对象,sync是Sync类型。CountDownLatch的Sync是实例类,它继承于AQS。

CyclicBarrier Semaphore是一个计数信号量,它的本质是一个共享锁。信号量维护了一个信号量许可集。线程可以通过调用acquire()来获取信号量的许可;当信号量中有可用的许可时,线程能获取该许可;否则线程必须等待,直到有可用的许可为止。线程可以通过release()来释放它所持有的信号量许可。 Semaphore的UML类图如下: b79b4a2bfe3d20de7a2aaa4d92898672.jpeg

和ReentrantLock一样,Semaphore包含了sync对象,sync是Sync类型;而且,Sync也是一个继承于AQS的抽象类。Sync也包括公平信号量FairSync和非公平信号量NonfairSync。