锁和AQS

定义

package java.util.concurrent.locks;
import java.util.concurrent.TimeUnit;

public interface Lock {

    void lock();

    void lockInterruptibly() throws InterruptedException;

    boolean tryLock();

    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;

    void unlock();

    Condition newCondition();
}

优点

  • 持续等待-lock()
  • 可中断-lockInterruptibly()
  • 非阻塞-tryLock() 没有公平可言!
  • 可超时-tryLock(long time, TimeUnit unit)
  • 非阻塞块使用
  • 任意链式锁:a+、b+、c+、a-、c-、b-

缺点

  • 有使用要求
 Lock l = ...;
 l.lock();
 try {
   // access the resource protected by this lock
 } finally {
   l.unlock();
 }}

特点

  • 定义了锁的基本使用需求方法:独占(如定时任务)或者保持时序(如计时器)

  • 普通接口+普通实现类:意味着任何人都可以实现

  • 纯code实现,没有特殊的JVM底层支持

  • 提供了抽象支持AbstractQueuedSynchronizer

如何实现

  • 使用一个标志位表示锁是否被获取
  • 使用一个数据结构保存等待的线程

AbstractQueuedSynchronizer

  • 使用int表示状态,支持重入
  • 使用CLH变种队列实现等待队列:双向链表,pre可靠,状态保存在前继节点中,有虚拟头节点
  • 支持独占和共享模式
  • 使用LockSupport进行线程阻塞

状态变量

  • 使用int表示状态,更具拓展性

CLH队列

  • 使用反向单链表实现
  • 公平锁
  • 不断自旋,获取前继节点状态
  • CLH详情链接

独占模式和共享模式

  • 独占模式只支持一个线程获取锁:ReentrantLock
  • 共享模式支持多个线程同时获取锁:Semaphore

LockSupport

  • park 阻塞线程
  • unpark 取消阻塞线程

AQS实现-ReentrantLock

  • 可重入,独占模式

  • 通过Sync继承AbstractQueuedSynchronizer,实现独占获取和释放

  • Sync具体实现分为公平和非公平两种,区别在于获取时是否能插队

  • ReentrantLock实现Lock接口,具体实现调用Sync

公平锁

lock细节

  1. 没人排队,尝试获取锁
  2. 自己在排队,重入
  3. 别人在排队,自己进入队列,设置pre状态,park

unlock细节

  1. 必须是获得锁的线程,不然报错
  2. 释放状态,如果完全释放,解除独占线程
  3. 如果完全释放,唤醒第一个等待线程

AQS实现-Semaphore

  • 不可重入,共享模式
  • 初始化一个状态值,获取时判断状态值是否超过最大值,超过获取失败,不超过获取成功

AQS实现-CountDownLatch

  • 初始化一个状态值,每次countDown的时候释放1
  • await等待获取锁,当countDown完成后,await获取锁成功

原文地址:https://www.cnblogs.com/zby9527/p/13385796.html