临界资源

  在多线程并发过程中,有可能会出现多个线程同时出现访问同一个共享,可变资源的情况。这个资源可能是变量、文件、对象等。

  共享:资源可以由多个线程同时访问

  可变:资源可以在其生命周期内修改

 

引发的问题:

  由于线程的过程是不可控的,所以需要采用同步机制来对协同对象可变状态的访问。

 

Java 中,提供了两种方式来实现同步互斥访问:synchronized 和 Lock
同步器的本质就是加锁

加锁目的

      序列化访问临界资源:即在任一时刻,只能有一个线程访问临界资源,也称为 同步互斥访问

 

第二节: 并发编程之synchronized/Lock和AQS详解

 

 

 

JAVA锁体系

第二节: 并发编程之synchronized/Lock和AQS详解

 

JAVA线程生命状态

第二节: 并发编程之synchronized/Lock和AQS详解

 

synchronized原理详解

      synchronized内置锁是一种对象锁,(锁的是对象而非引用),作用粒度是对象,可以用来实现对临界资源的同步互斥访问,是可重入的。

加锁的方式:

1. 同步实例方法    锁是当前实例对象

第二节: 并发编程之synchronized/Lock和AQS详解

2. 同步类方法    锁是当前类对象

第二节: 并发编程之synchronized/Lock和AQS详解

3. 同步代码块     锁是括号里面的对象

第二节: 并发编程之synchronized/Lock和AQS详解

 

 

 

synchronized不能跨方法保证原子性,那如何实现跨方法保证? --- Unsafe类monitorenter和monitorexit来实现。

第二节: 并发编程之synchronized/Lock和AQS详解

 

 

 

 

 

synchronized底层原理

synchronized是基于底层JVM内置锁实现,通过内部对象Monitor(监控器锁)实现,基于进入和退出Monitor对象实现方法和代码块同步,监视器锁的实现依赖底层操作系统的Mutex Lock(互斥锁)实现,它是一个重量级锁性能较低。
synchronized关键字被编译成字节码后会被翻译成monitorenter 和 monitorexit 两条指令分别在同步块逻辑代码的起始位置与结束位置。

第二节: 并发编程之synchronized/Lock和AQS详解

 

每个同步对象都有一个自己的Monitor(监视器锁),加锁过程如下图所示:

第二节: 并发编程之synchronized/Lock和AQS详解

 

 

 问题:synchronized加锁加在对象上,对象是如何记录锁状态的呢?

    -- 锁状态是被记录在每个对象的对象头(Mark Word)中.

 

对象的内存布局

HotSpot虚拟机中,对象在内存中存储的布局可以分为三块区域:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding).
   -- 对象头:比如 hash码,对象所属的年代,对象锁,锁状态标志,偏向锁(线程)ID,偏向时间,数组长度(数组对象)等
  -- 实例数据:即创建对象时,对象中成员变量,方法等
  -- 对齐填充:对象的大小必须是8字节的整数倍

第二节: 并发编程之synchronized/Lock和AQS详解

 

 

JVM内置锁在1.5之后版本做了重大的优化

如锁粗化(Lock Coarsening)、锁消除(Lock Elimination)、轻量级锁(Lightweight Locking)、偏向锁(Biased Locking)、适应性自旋(Adaptive Spinning)等技术来减少锁操作的开销,,内置锁的并发性能已经基本与Lock持平.

 

锁粗化举例:

第二节: 并发编程之synchronized/Lock和AQS详解        ===锁粗化===》   第二节: 并发编程之synchronized/Lock和AQS详解

 

 

锁消除举例:

第二节: 并发编程之synchronized/Lock和AQS详解

 

 

 

 逃逸分析

使用逃逸分析,编译器可以对代码做如下优化:

一、同步省略。如果一个对象被发现只能从一个线程被访问到,那么对于这个对象的操作可以不考虑同步。

二、将堆分配转化为栈分配。如果一个对象在子程序中被分配,要使指向该对象的指针永远 不会逃逸,对象可能是栈分配的候选,而不是堆分配。

三、分离对象或标量替换。有的对象可能不需要作为一个连续的内存结构存在也可以被访问 到,那么对象的部分(或全部)可以不存储在内存,而是存储在CPU寄存器中

 

在Java代码运行时,通过JVM参数可指定是否开启逃逸分析,

-XX:+DoEscapeAnalysis : 表示开启逃逸分析 ­

-XX:­DoEscapeAnalysis : 表示关闭逃逸分析 

从jdk 1.7开始已经默认开始逃逸分析,如需关闭,需要指定­-XX:DoEscapeAnalysis

 

public class StackAllocTest {

    /**
     * 进行两种测试
     * 关闭逃逸分析,同时调大堆空间,避免堆内GC的发生,如果有GC信息将会被打印出来
     * VM运行参数:-Xmx4G -Xms4G -XX:-DoEscapeAnalysis -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError
     *
     * 开启逃逸分析
     * VM运行参数:-Xmx4G -Xms4G -XX:+DoEscapeAnalysis -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError
     *
     * 执行main方法后
     * jps 查看进程
     * jmap -histo 进程ID
     */

    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        for (int i = 0; i < 500000; i++) {
            alloc();
        }
        long end = System.currentTimeMillis();
        //查看执行时间
        System.out.println("cost-time " + (end - start) + " ms");
        try {
            Thread.sleep(100000);
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }
    }


    private static TulingStudent alloc() {
        //Jit对编译时会对代码进行 逃逸分析
        //并不是所有对象存放在堆区,有的一部分存在线程栈空间
        TulingStudent student = new TulingStudent();
        return student;
    }

    static class TulingStudent {
        private String name;
        private int age;
    }
}

关闭逃逸分析:

关闭逃逸分析,同时调大堆空间,避免堆内GC的发生,如果有GC信息将会被打印出来  
VM运行参数:-Xmx4G -Xms4G -XX:-DoEscapeAnalysis -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError

第二节: 并发编程之synchronized/Lock和AQS详解

 

执行结果:

第二节: 并发编程之synchronized/Lock和AQS详解

 

查看线程 jps

第二节: 并发编程之synchronized/Lock和AQS详解

 

 

 

分析进程  jmap -histo + 进程号

第二节: 并发编程之synchronized/Lock和AQS详解

 

 

 

打开逃逸分析:

开启逃逸分析,同时调大堆空间,避免堆内GC的发生,如果有GC信息将会被打印出来
VM运行参数:-Xmx4G -Xms4G -XX:+DoEscapeAnalysis -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError

 第二节: 并发编程之synchronized/Lock和AQS详解

 第二节: 并发编程之synchronized/Lock和AQS详解

 

 第二节: 并发编程之synchronized/Lock和AQS详解

 

问题: 是不是实例对象都存放在堆区? 

-- 不一定,如果实例对象没有线程逃逸行为,实例对象存放在堆区;如果有线程逃逸行为,则有可能部分存在线程栈中。

   如果实例对象存储在堆区,实例对象内存存在堆区,实例的引用存在栈上,实例的元数据class存放在方法区或元空间。

 

 

第二节: 并发编程之synchronized/Lock和AQS详解

 第二节: 并发编程之synchronized/Lock和AQS详解

 第二节: 并发编程之synchronized/Lock和AQS详解

 

 

第二节: 并发编程之synchronized/Lock和AQS详解

轻量级锁使用场景:

 

第二节: 并发编程之synchronized/Lock和AQS详解

 

第二节: 并发编程之synchronized/Lock和AQS详解

 

 

 

锁的升级过程拆分

JVM锁的膨胀升级过程场景一:

第二节: 并发编程之synchronized/Lock和AQS详解

 

 

JVM锁的膨胀升级过程场景二:

第二节: 并发编程之synchronized/Lock和AQS详解

 

 

 

锁的升级过程明细如下:

第二节: 并发编程之synchronized/Lock和AQS详解

 

 

第二部分: LOCK&AQS  -- 如 独占锁:ReentrantLock  读写锁:ReentrantReadWriterLock

AbstractQueuedSynchronizer(AQS)  同步框架器

并发之父 Doug Lea

Java并发编程核心在于java.concurrent.util包而juc当中的大多数同步器实现都是围绕着共同的基础行为,比如等待队列、条件队列、独占获取、共享获取等,而这个行为的抽象就是基于AbstractQueuedSynchronizer简称AQS,

AQS定义了一套多线程访问共享资源的同步器框架,是一个依赖状态(state)的同步器

于AQS框架实现

  • 一般通过定义内部类Sync继承AQS
  • 将同步器所有调用都映射到Sync对应的方法

AQS内部维护属性 volatile int state (32位)

  • state表示资源的可用状态

State三种访问方式

  • getState()、setState()、compareAndSetState()

AQS定义两种资源共享方式

  • Exclusive-独占,只有一个线程能执行,如ReentrantLock
  • Share-共享,多个线程可以同时执行,如Semaphore/CountDownLatch

AQS定义两种队列

  • 同步等待队列  CLH对列(双向链表)
  • 条件等待队列

不同的自定义同步器争用共享资源的方式也不同。自定义同步器在实现时只需要实现共享资源state的获取与释放方式即可,至于具体线程等待队列的维护(如获取资源失败入队/唤醒出队等),AQS已经在顶层实现好了。

实现时主要实现以下几种方法:

  • isHeldExclusively():该线程是否正在独占资源。只有用到condition才需要去实现它。
  • tryAcquire(int):独占方式。尝试获取资源,成功则返回true,失败则返回false。
  • tryRelease(int):独占方式。尝试释放资源,成功则返回true,失败则返回false。
  • tryAcquireShared(int):共享方式。尝试获取资源。负数表示失败;0表示成功,但没有剩余可用资源;正数表示成功,且有剩余资源。
  • tryReleaseShared(int):共享方式。尝试释放资源,如果释放后允许唤醒后续等待结点返回true,否则返回false



AQS具备特性:

  • 阻塞等待队列                  
  • 共享/独占
  • 公平/非公平
  • 可重入
  • 允许中断

问题 : 阻塞等待队列,是如何实现的?  -- 通过魔术类 UnSafe.park() /  UnSafe.unpark()  

AbstractQueuedSynchronizer.java 

第二节: 并发编程之synchronized/Lock和AQS详解

 

 

 第二节: 并发编程之synchronized/Lock和AQS详解

 

问题 : 公平和非公平锁如何实现?

第二节: 并发编程之synchronized/Lock和AQS详解

公平锁:     private ReentrantLock lock = new ReentrantLock(true);

非公平锁:  private ReentrantLock lock = new ReentrantLock(false); 

 

 

问题 : 共享锁和独占锁如何区分的?

AbstractQueuedSynchronizer.java 
第二节: 并发编程之synchronized/Lock和AQS详解

   第二节: 并发编程之synchronized/Lock和AQS详解

   第二节: 并发编程之synchronized/Lock和AQS详解

问题 : AQS定义两种资源共享方式?   --- 共享  和 独占

  • Exclusive -- 独占,只有一个线程能执行,如ReentrantLock
  • share -- 共享,多个线程可以同时执行,如Semaphore / CountDownLatch

AQS定义的两种对列 

  • 同步等待队列  CLH(双向链表)
  • 条件等待队列

同步等待队列详解

AQS当中的同步等待队列也称CLH队列,CLH队列是Craig、Landin、Hagersten三人发明的一种基于双向链表数据结构的队列
是FIFO先入先出线程等待队列,Java中的CLH队列是CLH队列的一个变种,线程由原自旋机制改为阻塞机制

第二节: 并发编程之synchronized/Lock和AQS详解

 

 

 

 条件等待队列

Condition是一个多线程间协调通信的工具类,使得某个,或者某些线程一起等待某个条件(Condition),只有当该条件具备时,这些等待线程才会被唤醒,从而重新争夺锁。

第二节: 并发编程之synchronized/Lock和AQS详解

 

 

 

 

常见各种锁详解:

 

第二节: 并发编程之synchronized/Lock和AQS详解

 

第二节: 并发编程之synchronized/Lock和AQS详解

第二节: 并发编程之synchronized/Lock和AQS详解

 

 

 第二节: 并发编程之synchronized/Lock和AQS详解

第二节: 并发编程之synchronized/Lock和AQS详解

 

可重入锁举例:

import java.util.concurrent.locks.ReentrantLock;

/**
 *  可重入锁
 */
public class LockTemplete {
    private Integer counter = 0;
    /**
     * 可重入锁,公平锁
     * 公平锁,
     * 非公平锁
     * 需要保证多个线程使用的是同一个锁
     *
     *
     * synchronized是否可重入?
     * 虚拟机,在ObjectMonitor.hpp定义了synchronized他怎么取重入加锁 ..。hotspot源码
     * counter +1
     * 基于AQS 去实现加锁与解锁
     */
    private ReentrantLock lock = new ReentrantLock(true);

    /**
     * 需要保证多个线程使用的是同一个ReentrantLock对象
     * @return
     */
    public void modifyResources(String threadName){
        System.out.println("通知《管理员》线程:--->"+threadName+"准备打水");
        //默认创建的是独占锁,排它锁;同一时刻读或者写只允许一个线程获取锁
        lock.lock();
            System.out.println("线程:--->"+threadName+"第一次加锁");
            counter++;
            System.out.println("线程:"+threadName+"打第"+counter+"桶水");
            //重入该锁,我还有一件事情要做,没做完之前不能把锁资源让出去
            lock.lock();
            System.out.println("线程:--->"+threadName+"第二次加锁");
            counter++;
            System.out.println("线程:"+threadName+"打第"+counter+"桶水");
            lock.unlock();
            System.out.println("线程:"+threadName+"释放一个锁");
        lock.unlock();
        System.out.println("线程:"+threadName+"释放一个锁");
    }


    public static void main(String[] args){
        LockTemplete tp = new LockTemplete();

        new Thread(()->{
            String threadName = Thread.currentThread().getName();
            tp.modifyResources(threadName);
        },"Thread A").start();

        new Thread(()->{
            String threadName = Thread.currentThread().getName();
            tp.modifyResources(threadName);
        },"Thread B").start();
    }

}

 

 

源码解析及中文解析:

 

ReentrantLock.java 
package com.it.edu.aqs;
/*
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */

/*
 *
 *
 *
 *
 *
 * Written by Doug Lea with assistance from members of JCP JSR-166
 * Expert Group and released to the public domain, as explained at
 * http://creativecommons.org/publicdomain/zero/1.0/
 */

import java.util.Collection;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

/**
 * A reentrant mutual exclusion {@link Lock} with the same basic
 * behavior and semantics as the implicit monitor lock accessed using
 * {@code synchronized} methods and statements, but with extended
 * capabilities.
 *
 * <p>A {@code ReentrantLock} is <em>owned</em> by the thread last
 * successfully locking, but not yet unlocking it. A thread invoking
 * {@code lock} will return, successfully acquiring the lock, when
 * the lock is not owned by another thread. The method will return
 * immediately if the current thread already owns the lock. This can
 * be checked using methods {@link #isHeldByCurrentThread}, and {@link
 * #getHoldCount}.
 *
 * <p>The constructor for this class accepts an optional
 * <em>fairness</em> parameter.  When set {@code true}, under
 * contention, locks favor granting access to the longest-waiting
 * thread.  Otherwise this lock does not guarantee any particular
 * access order.  Programs using fair locks accessed by many threads
 * may display lower overall throughput (i.e., are slower; often much
 * slower) than those using the default setting, but have smaller
 * variances in times to obtain locks and guarantee lack of
 * starvation. Note however, that fairness of locks does not guarantee
 * fairness of thread scheduling. Thus, one of many threads using a
 * fair lock may obtain it multiple times in succession while other
 * active threads are not progressing and not currently holding the
 * lock.
 * Also note that the untimed {@link #tryLock()} method does not
 * honor the fairness setting. It will succeed if the lock
 * is available even if other threads are waiting.
 *
 * <p>It is recommended practice to <em>always</em> immediately
 * follow a call to {@code lock} with a {@code try} block, most
 * typically in a before/after construction such as:
 *
 *  <pre> {@code
 * class X {
 *   private final ReentrantLock lock = new ReentrantLock();
 *   // ...
 *
 *   public void m() {
 *     lock.lock();  // block until condition holds
 *     try {
 *       // ... method body
 *     } finally {
 *       lock.unlock()
 *     }
 *   }
 * }}</pre>
 *
 * <p>In addition to implementing the {@link Lock} interface, this
 * class defines a number of {@code public} and {@code protected}
 * methods for inspecting the state of the lock.  Some of these
 * methods are only useful for instrumentation and monitoring.
 *
 * <p>Serialization of this class behaves in the same way as built-in
 * locks: a deserialized lock is in the unlocked state, regardless of
 * its state when serialized.
 *
 * <p>This lock supports a maximum of 2147483647 recursive locks by
 * the same thread. Attempts to exceed this limit result in
 * {@link Error} throws from locking methods.
 *
 * @since 1.5
 * @author Doug Lea
 */
public class ReentrantLock implements Lock, java.io.Serializable {
    private static final long serialVersionUID = 7373984872572414699L;
    /**
     * 内部调用AQS的动作,都基于该成员属性实现
     */
    private final Sync sync;

    /**
     * ReentrantLock锁同步操作的基础类Sync,继承自AQS框架.
     * 该类有两个继承类,1、NonfairSync 非公平锁,2、FairSync公平锁
     */
        abstract static class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = -5179523762034025860L;

        /**
         * 加锁的具体行为由子类实现
         */
        abstract void lock();

        /**
         * 尝试获取非公平锁
         */
        final boolean nonfairTryAcquire(int acquires) {
            //acquires = 1
            final Thread current = Thread.currentThread();
            int c = getState();
            /**
             * 不需要判断同步队列(CLH)中是否有排队等待线程
             * 判断state状态是否为0,不为0可以加锁
             */
            if (c == 0) {
                //unsafe操作,cas修改state状态
                if (compareAndSetState(0, acquires)) {
                    //独占状态锁持有者指向当前线程
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            /**
             * state状态不为0,判断锁持有者是否是当前线程,
             * 如果是当前线程持有 则state+1
             */
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            //加锁失败
            return false;
        }

        /**
         * 释放锁
         */
        protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        }

        /**
         * 判断持有独占锁的线程是否是当前线程
         */
        protected final boolean isHeldExclusively() {
            return getExclusiveOwnerThread() == Thread.currentThread();
        }

        //返回条件对象
        final ConditionObject newCondition() {
            return new ConditionObject();
        }


        final Thread getOwner() {
            return getState() == 0 ? null : getExclusiveOwnerThread();
        }

        final int getHoldCount() {
            return isHeldExclusively() ? getState() : 0;
        }

        final boolean isLocked() {
            return getState() != 0;
        }

        /**
         * Reconstitutes the instance from a stream (that is, deserializes it).
         */
        private void readObject(java.io.ObjectInputStream s)
                throws java.io.IOException, ClassNotFoundException {
            s.defaultReadObject();
            setState(0); // reset to unlocked state
        }
    }

    /**
     * 非公平锁
     */
    static final class NonfairSync extends Sync {
        private static final long serialVersionUID = 7316153563782823691L;
        /**
         * 加锁行为
         */
        final void lock() {
            /**
             * 第一步:直接尝试加锁
             * 与公平锁实现的加锁行为一个最大的区别在于,此处不会去判断同步队列(CLH队列)中
             * 是否有排队等待加锁的节点,上来直接加锁(判断state是否为0,CAS修改state为1)
             * ,并将独占锁持有者 exclusiveOwnerThread 属性指向当前线程
             * 如果当前有人占用锁,再尝试去加一次锁
             */
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                //AQS定义的方法,加锁
                acquire(1);
        }

        /**
         * 父类AbstractQueuedSynchronizer.acquire()中调用本方法
         */
        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
    }

    /**
     * 公平锁
     */
    static final class FairSync extends Sync {
        private static final long serialVersionUID = -3000897897090466540L;

        final void lock() {
            acquire(1);
        }

        /**
         * 重写aqs中的方法逻辑
         * 尝试加锁,被AQS的acquire()方法调用
         */
        protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                /**
                 * 与非公平锁中的区别,需要先判断队列当中是否有等待的节点
                 * 如果没有则可以尝试CAS获取锁
                 */
                if (!hasQueuedPredecessors() &&
                        compareAndSetState(0, acquires)) {
                    //独占线程指向当前线程
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0)
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }
    }

    /**
     * 默认构造函数,创建非公平锁对象
     */
    public ReentrantLock() {
        sync = new NonfairSync();
    }

    /**
     * 根据要求创建公平锁或非公平锁
     */
    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }

    /**
     * 加锁
     */
    public void lock() {
        sync.lock();
    }

    /**
     * 尝试获去取锁,获取失败被阻塞,线程被中断直接抛出异常
     */
    public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }

    /**
     * 尝试加锁
     */
    public boolean tryLock() {
        return sync.nonfairTryAcquire(1);
    }

    /**
     * 指定等待时间内尝试加锁
     */
    public boolean tryLock(long timeout, TimeUnit unit)
            throws InterruptedException {
        return sync.tryAcquireNanos(1, unit.toNanos(timeout));
    }

    /**
     * 尝试去释放锁
     */
    public void unlock() {
        sync.release(1);
    }

    /**
     * 返回条件对象
     */
    public Condition newCondition() {
        return sync.newCondition();
    }

    /**
     * 返回当前线程持有的state状态数量
     */
    public int getHoldCount() {
        return sync.getHoldCount();
    }

    /**
     * 查询当前线程是否持有锁
     */
    public boolean isHeldByCurrentThread() {
        return sync.isHeldExclusively();
    }

    /**
     * 状态表示是否被Thread加锁持有
     */
    public boolean isLocked() {
        return sync.isLocked();
    }

    /**
     * 是否公平锁?是返回true 否则返回 false
     */
    public final boolean isFair() {
        return sync instanceof FairSync;
    }

    /**
     * Returns the thread that currently owns this lock, or
     * {@code null} if not owned. When this method is called by a
     * thread that is not the owner, the return value reflects a
     * best-effort approximation of current lock status. For example,
     * the owner may be momentarily {@code null} even if there are
     * threads trying to acquire the lock but have not yet done so.
     * This method is designed to facilitate construction of
     * subclasses that provide more extensive lock monitoring
     * facilities.
     *
     * @return the owner, or {@code null} if not owned
     */
    protected Thread getOwner() {
        return sync.getOwner();
    }

    /**
     * 判断队列当中是否有在等待获取锁的Thread节点
     */
    public final boolean hasQueuedThreads() {
        return sync.hasQueuedThreads();
    }

    /**
     * 当前线程是否在同步队列中等待
     */
    public final boolean hasQueuedThread(Thread thread) {
        return sync.isQueued(thread);
    }

    /**
     * Returns an estimate of the number of threads waiting to
     * acquire this lock.  The value is only an estimate because the number of
     * threads may change dynamically while this method traverses
     * internal data structures.  This method is designed for use in
     * monitoring of the system state, not for synchronization
     * control.
     *
     * @return the estimated number of threads waiting for this lock
     */
    public final int getQueueLength() {
        return sync.getQueueLength();
    }

    /**
     * 返回Thread集合,排队中的所有节点Thread会被返回
     */
    protected Collection<Thread> getQueuedThreads() {
        return sync.getQueuedThreads();
    }

    /**
     * 条件队列当中是否有正在等待的节点
     */
    public boolean hasWaiters(Condition condition) {
        if (condition == null)
            throw new NullPointerException();
        if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
            throw new IllegalArgumentException("not owner");
        return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition);
    }

    /**
     * Returns an estimate of the number of threads waiting on the
     * given condition associated with this lock. Note that because
     * timeouts and interrupts may occur at any time, the estimate
     * serves only as an upper bound on the actual number of waiters.
     * This method is designed for use in monitoring of the system
     * state, not for synchronization control.
     *
     * @param condition the condition
     * @return the estimated number of waiting threads
     * @throws IllegalMonitorStateException if this lock is not held
     * @throws IllegalArgumentException if the given condition is
     *         not associated with this lock
     * @throws NullPointerException if the condition is null
     */
    public int getWaitQueueLength(Condition condition) {
        if (condition == null)
            throw new NullPointerException();
        if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
            throw new IllegalArgumentException("not owner");
        return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition);
    }

    /**
     * Returns a collection containing those threads that may be
     * waiting on the given condition associated with this lock.
     * Because the actual set of threads may change dynamically while
     * constructing this result, the returned collection is only a
     * best-effort estimate. The elements of the returned collection
     * are in no particular order.  This method is designed to
     * facilitate construction of subclasses that provide more
     * extensive condition monitoring facilities.
     *
     * @param condition the condition
     * @return the collection of threads
     * @throws IllegalMonitorStateException if this lock is not held
     * @throws IllegalArgumentException if the given condition is
     *         not associated with this lock
     * @throws NullPointerException if the condition is null
     */
    protected Collection<Thread> getWaitingThreads(Condition condition) {
        if (condition == null)
            throw new NullPointerException();
        if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
            throw new IllegalArgumentException("not owner");
        return sync.getWaitingThreads((AbstractQueuedSynchronizer.ConditionObject)condition);
    }

    /**
     * Returns a string identifying this lock, as well as its lock state.
     * The state, in brackets, includes either the String {@code "Unlocked"}
     * or the String {@code "Locked by"} followed by the
     * {@linkplain Thread#getName name} of the owning thread.
     *
     * @return a string identifying this lock, as well as its lock state
     */
    public String toString() {
        Thread o = sync.getOwner();
        return super.toString() + ((o == null) ?
                "[Unlocked]" :
                "[Locked by thread " + o.getName() + "]");
    }
}
View Code

相关文章:

  • 2021-10-09
  • 2021-08-04
  • 2021-05-22
猜你喜欢
  • 2022-12-23
  • 2021-10-04
  • 2021-05-16
  • 2021-06-27
  • 2021-08-11
  • 2021-04-20
  • 2021-09-06
相关资源
相似解决方案