第5章| Java中的锁

本章主要介绍Java并发包(concurrent)下与锁相关的API和组件的使用及实现细节。

Lock接口

  1. :用来控制多个线程访问共享资源的方式,通常一个锁能防止多个线程同时访问共享资源,但读写锁可以允许多个线程并发地访问共享资源。
  2. JDK1.5前用synchronized实现锁功能,之后Lock提供了与synchronized类似的同步功能,尽管使用时需要显示地释放与获取锁,但与其同时也新增了获取锁与释放锁的可操作性可中断地获取锁超时获取锁等特性
  3. Lock的使用方式:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // 实例化锁对象
    Lock lock = new ReentrantLock();
    // 获取锁
    lock.lock();
    try{
    }finally{
    // 释放锁
    lock.unlock();
    }

注意:不要在try块中获取锁,因为如果获取锁时发生了异常,抛出异常时,会导致锁无故释放。

  1. Lock接口比synchronized多的特性,见下表
特性 描述
尝试非阻塞地获取锁 当前线程尝试获取锁,如果这一时刻锁没有被其他线程获取到,则成功获取并持有锁
能中断地获取锁 获取锁的同时可以响应中断,此时抛出中断异常,同时释放锁
超时获取锁 在指定的截止时间内获取锁,如果超时了无法获取锁,则返回

Lock接口实现基本都是通过聚合了一个同步器的子类来实现访问控制的

队列同步器AbstractQueueSynchronizer

  1. 作用:构建锁或其他同步组件的基础框架,其用一个into变量表示同步状态,通过内置的FIFO队列完成资源获取线程的排队工作。
  2. 同步器的主要实现方法为继承,一般推荐子类定义为自定义同步组件的静态内部类
  3. 队列同步器本身没有任何同步接口,仅定义了若干同步状态获取与释放的方法供自定义同步组件使用;
  4. 队列同步器既可以支持独占式获取同步状态,也可以支持共享式获取同步状态;
  5. 同步器是实现锁的关键,实现锁的过程中聚合同步器,利用同步器实现锁的语义。同步器与锁的关系: ①锁面向使用者,定义了使用者与锁交互的接口,隐藏了实现细节;②同步器面向锁的实现者,简化了锁的实现方式,屏蔽了同步状态管理、线程排队、等待与唤醒等底层操作。③锁与同步器隔离了使用者与实现者所要关注的领域。

队列同步器的接口与示例

前面说道队列同步器的使用方式为继承,也就是使用者需要重写指定的方法,随后将同步器组合在自定义同步组件的实现中,并调用同步器提供的模板方法,这些模板方法会调用使用者重写的方法。

  1. 有3个方法可以用来访问或修改同步状态:
  • getState():获取同步状态
  • setState(int newState):设定当前同步状态
  • compareAndSetState(int expect, int update):使用CAS设置当前状态,该方法可以保证设置的原子性
  1. 队列同步器提供的模板方法主要分为3类
  • 独占式获取与释放同步状态
  • 共享式获取与释放同步状态
  • 查询同步队列中的等待线程情况

队列同步器的实现分析

同步队列

  1. 实现原理
    同步器依赖内部的同步队列(一个FIFO双向队列)来完成同步状态的管理,当前线程获取同步状态失败时,同步器会将当前线程以及等待状态等信息构造成为一个节点(Node)并将其加入同步队列,同时会阻塞当前线程,当同步状态释放时,会把首节点中的线程唤醒,使其再次尝试获取同步状态。
  2. 节点是构成同步队列的基础,其基本结构如下图所是:
    同步队列的基本结构

其中同步器将节点加入到同步队列的过程如下图所示:
 节点加入到同步队列

独占式同步状态获取与释放

  1. 同步器的acquire(int arg)方法可以获取同步状态,该方法对中断不敏感(线程获取同步状态失败后进入同步队列中,后续对线程进行中断操作时,线程不会从同步队列中移出);
  2. 在acquireQueued(final Node node, int arg)方法中,当前线程在“死循环”中尝试获取同步状态,而只有前驱节点是头节点才能够尝试获取同步状态,这样做的原因有二:
    ① 头节点是成功获取到同步状态的节点,而头节点的线程释放了同步状态之后,将唤醒其后继节点,后继节点的线程被唤醒后需要检查自己的前驱节点是否是头节点。
    ② 维护同步队列的FIFO原则。
  3. 独占式同步状态获取流程,也就是acquire(int arg)方法调用流程,如下图所示:
    独占式同步状态获取流程

    共享式同步状态获取与释放

独占式超时获取同步状态

重入锁ReentrantLock

名词解释:是支持重进入的锁,它表示该锁能够支持一个线程对
资源的重复加锁。除此之外,该锁的还支持获取锁时的公平和非公平性选择。

码哥 wechat
欢迎关注个人订阅号:「码上行动GO」