常见JUC类代码解析

ReentrantLock

ReetrantLock是一种类似Synchronized的一种互斥锁实现代码同步执行的方式。它是java语言自己实比Synchronized使用更加灵活.

ReetrantLock和Sychronized区别

  1. ReentrantLock是java自己实现的一种同步锁机制,Synchronized是调用本地方法实现
  2. ReentrantLock 支持公平锁和非公平锁,Synchronized只支持 非公平锁
  3. ReentrantLock 要主动通过unlock释放锁,Synchronized不需要释放锁
  4. ReentrantLock可以通过tryLock方法返回boolean来尝试获取锁,可以根据返回结果决定是否往下执行,Synchronized获取不到锁,就会一直尝试获取锁,不能通过程序控制。

示例代码

public class RentrantLockDemo {

    public static void main(String[] args) {
        Lock lock = new ReentrantLock();
        Condition condition = lock.newCondition();
        int maxLength = 5;
        Queue<String> data = new LinkedList<String>();
        Producer producer = new Producer(lock, condition, maxLength, data);
        Consumer consumer = new Consumer(lock, condition, maxLength, data);
        new Thread(producer).start();
        new Thread(consumer).start();
    }


}

class Producer implements Runnable {
    private Lock lock;
    private Condition condition;
    private int maxLength;
    private Queue<String> data;

    public Producer(Lock lock, Condition condition, int maxLength, Queue<String> data) {
        this.lock = lock;
        this.condition = condition;
        this.maxLength = maxLength;
        this.data = data;
    }

    @Override
    public void run() {
        int count = 0;
        while (true) {
            //加锁
            lock.lock();
            while (data.size() == maxLength) {
                System.out.println("生产者队列满了,等待");
                try {
                    //手动await进入等待队列,释放线程 相当于Synchronized的wait
                    condition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("生产者生产消息:" + (++count));
            data.add(String.valueOf(count));
            //唤醒其他线程等待线程 相当于Sychronized的notify
            condition.signal();
            //释放锁
            lock.unlock();
        }
    }
}


class Consumer implements Runnable {
    private Lock lock;
    private Condition condition;
    private int maxLength;
    private Queue<String> data;

    public Consumer(Lock lock, Condition condition, int maxLength, Queue<String> data) {
        this.lock = lock;
        this.condition = condition;
        this.maxLength = maxLength;
        this.data = data;
    }


    @Override
    public void run() {
        while (true) {
            lock.lock();
            while (data.size() == 0) {
                System.out.println("消费者队列空了,等待");
                try {
                    condition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("消费者消费消息:" + data.remove());
            condition.signal();
            lock.unlock();
        }
    }
}

类图

image-20210705195144065

核心对象

  • AbstractOwnableSynchronizer: 主要用于存储ReetrantLock获取锁的线程,和获取锁线程的state(在ReetrantLock特指重入次数)

  • AbstractQueueSynchronizer: AQS队列,里面维护了双向链表和单向链表以及操作的Api,用于实现ReetrantLock锁,和Condition阻塞队列,实现互斥锁和锁等待的功能。

  • Node 节点信息,里面包含Thread和state 是对线程 和 线程状态的一个封装

  • Sync接口是ReetrantLock的内部类接口,

    它有两个内部类实现 NonfairSync非公平锁实现,FairSync公平锁的实现

核心流程

以非公平锁的实现为例

static final class NonfairSync extends Sync {
    private static final long serialVersionUID = 7316153563782823691L;

    /**
         * Performs lock.  Try immediate barge, backing up to normal
         * acquire on failure.
         */
    final void lock() {
        //无锁状态下尝试获取锁
        if (compareAndSetState(0, 1))
            setExclusiveOwnerThread(Thread.currentThread());
        else
            //竞争无锁失败,进入锁的重入或阻塞
            acquire(1);
    }

    protected final boolean tryAcquire(int acquires) {
        return nonfairTryAcquire(acquires);
    }
}
public final void acquire(int arg) {
    if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}

三个核心方法

  • tryAcquire
假设ThreadA执行tryAcquire成功

image-20210705204543460

final boolean nonfairTryAcquire(int acquires) {
    final Thread current = Thread.currentThread();
    //获取当前持有锁线程的重入次数
    int c = getState();
    //如果重入次数为0 无锁,尝试竞争锁
    if (c == 0) {
        if (compareAndSetState(0, acquires)) {
            setExclusiveOwnerThread(current);
            return true;
        }
    }
    //如果持有锁的线程 和 当前线程是同一线程 增加重入次数返回true结束方法
    else if (current == getExclusiveOwnerThread()) {
        int nextc = c + acquires;
        if (nextc < 0) // overflow
            throw new Error("Maximum lock count exceeded");
        setState(nextc);
        return true;
    }
    //返回false 进入线程阻塞逻辑
 	return false;
}
  • (tryAcquire return false)=> addWaiter
private Node addWaiter(Node mode) {
    //mode 为 Node.EXCLUSIVE 代表排它锁的实现 
    Node node = new Node(Thread.currentThread(), mode);
    // Try the fast path of enq; backup to full enq on failure
    //AQS队列中已经存在节点 直接尝试加入到AQS尾部
    Node pred = tail;
    if (pred != null) {
        node.prev = pred;
        if (compareAndSetTail(pred, node)) {
            pred.next = node;
            return node;
        }
    }
    //加入尾部节点失败或者AQS队列为空进入enq自旋直到将node加入到AQS尾节点
    enq(node);
    return node;
}

//将node加入到尾节点,同时返回上一次的尾结点
private Node enq(final Node node) {
    for (;;) {
        Node t = tail;
        if (t == null) { // Must initialize
            if (compareAndSetHead(new Node()))
                tail = head;
        } else {
            node.prev = t;
            if (compareAndSetTail(t, node)) {
                t.next = node;
                return t;
            }
        }
    }
}
ThreadB 和 ThreadC 尝试抢占锁失败,加入到AQS队列

image-20210705205559190

  • 挂起阻塞队列中的线程 acquireQueued
final boolean acquireQueued(final Node node, int arg) {
    boolean failed = true;
    try {
        boolean interrupted = false;
        for (;;) {
            final Node p = node.predecessor();
            if (p == head && tryAcquire(arg)) {
                setHead(node);
                p.next = null; // help GC
                failed = false;
                return interrupted;
            }
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt())
                interrupted = true;
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}
ThreadB 和 ThreadC park 挂起线程

image-20210705210016401

ThreadA执行完任务释放锁,并唤醒AQS队列节点
//unlock -> 执行release方法 每次传入1
public final boolean release(int arg) {
    //尝试释放锁 如果释放锁成功 即state=0 exclusiveOwnerThread=null
    if (tryRelease(arg)) {
        Node h = head;
        if (h != null && h.waitStatus != 0)
            //唤醒AQS的head的下一个线程
            unparkSuccessor(h);
        return true;
    }
    return false;
}

rotected final boolean tryRelease(int releases) {
    int c = getState() - releases;
    if (Thread.currentThread() != getExclusiveOwnerThread())
        throw new IllegalMonitorStateException();
    boolean free = false;
    //如果state=0 exclusiveOwnerThread=null 则释放线程成功返回true
    if (c == 0) {
        free = true;
        setExclusiveOwnerThread(null);
    }
    setState(c);
    return free;
}
//唤醒AQS线程逻辑
//传入node为AQS的head
private void unparkSuccessor(Node node) {
        /*
         * If status is negative (i.e., possibly needing signal) try
         * to clear in anticipation of signalling.  It is OK if this
         * fails or if status is changed by waiting thread.
         */
        int ws = node.waitStatus;
        if (ws < 0)
            //尝试将haed的waitState 设置为 0
            compareAndSetWaitStatus(node, ws, 0);

        /*
         * Thread to unpark is held in successor, which is normally
         * just the next node.  But if cancelled or apparently null,
         * traverse backwards from tail to find the actual
         * non-cancelled successor.
         */
        //拿到head的下一个节点
        Node s = node.next;
        if (s == null || s.waitStatus > 0) {
            s = null;
            //从尾部向头部遍历,找到一个SINGLE状态的有效节点节点
            for (Node t = tail; t != null && t != node; t = t.prev)
                if (t.waitStatus <= 0)
                    s = t;
        }
        if (s != null)
            //唤醒上面的有效节点
            LockSupport.unpark(s.thread);
    }

    /**
     * Release action for shared mode -- signals successor and ensures
     * propagation. (Note: For exclusive mode, release just amounts
     * to calling unparkSuccessor of head if it needs signal.)
     */
    private void doReleaseShared() {
        /*
         * Ensure that a release propagates, even if there are other
         * in-progress acquires/releases.  This proceeds in the usual
         * way of trying to unparkSuccessor of head if it needs
         * signal. But if it does not, status is set to PROPAGATE to
         * ensure that upon release, propagation continues.
         * Additionally, we must loop in case a new node is added
         * while we are doing this. Also, unlike other uses of
         * unparkSuccessor, we need to know if CAS to reset status
         * fails, if so rechecking.
         */
        for (;;) {
            Node h = head;
            if (h != null && h != tail) {
                int ws = h.waitStatus;
                if (ws == Node.SIGNAL) {
                    if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
                        continue;            // loop to recheck cases
                    unparkSuccessor(h);
                }
                else if (ws == 0 &&
                         !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
                    continue;                // loop on failed CAS
            }
            if (h == head)                   // loop if head changed
                break;
        }
    }
回到线程park是的状态
public final void acquire(int arg) {
    if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}

final boolean acquireQueued(final Node node, int arg) {
    boolean failed = true;
    try {
        boolean interrupted = false;
        for (;;) {
            final Node p = node.predecessor();
            if (p == head && tryAcquire(arg)) {
                setHead(node);
                p.next = null; // help GC
                failed = false;
                return interrupted;
            }
            if (shouldParkAfterFailedAcquire(p, node) &&
                //此处park阻塞线程
                parkAndCheckInterrupt())
                interrupted = true;
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}

//线程恢复之后执行 
private final boolean parkAndCheckInterrupt() {
    LockSupport.park(this);
    //返回线程的中断标识, 并将线程的中断标识复位
    return Thread.interrupted();
}
//这是因为park的阻塞和我们wait、sleep不一样,这两种阻塞,如果被外部线程中断,会自动唤醒线程,并抛出InterruptException异常复位中断标识,而park方法并没有这类实现,需要我们手动实现中断响应
public static void park(Object blocker) {
    Thread t = Thread.currentThread();
    setBlocker(t, blocker);
    UNSAFE.park(false, 0L);
    setBlocker(t, null);
}

//然后自旋方法内进入下次循环
for (;;) {
    final Node p = node.predecessor();
    //将当前节点的threadB set到exclusiveOwnerThread
    if (p == head && tryAcquire(arg)) {
        //将原来的threadB的node设置为AQS头结点,setThread=null
        setHead(node);
        p.next = null; // help GC
        failed = false;
        //终止自旋,返回中断标识
        return interrupted;
    }
    if (shouldParkAfterFailedAcquire(p, node) &&
        parkAndCheckInterrupt())
        interrupted = true;
}
//返回中断标识后 调用selfInterrupt
static void selfInterrupt() {
    //将复位后的标识再次中断
    Thread.currentThread().interrupt();
}
//这个时候我们可以在lock方法中通过Thread.currentThread.isInterrupted响应中断

Condition

Condition是ReentrantLock的衍生对象,通过ReentrantLock.newCondition()创建Condition对象,在同步代码块内通过Condition.await() 可以主动释放线程cpu时间片,进入waiting状态,作用和Synchronized的wait/notify一样,Condition提供了await()/single(),来实现加锁同步代码的等待和唤醒机制。

示例代码

public class RentrantLockDemo {

    public static void main(String[] args) {
        Lock lock = new ReentrantLock();
        Condition condition = lock.newCondition();
        int maxLength = 5;
        Queue<String> data = new LinkedList<String>();
        Producer producer = new Producer(lock, condition, maxLength, data);
        Consumer consumer = new Consumer(lock, condition, maxLength, data);
        new Thread(producer).start();
        new Thread(consumer).start();
    }


}

class Producer implements Runnable {
    private Lock lock;
    private Condition condition;
    private int maxLength;
    private Queue<String> data;

    public Producer(Lock lock, Condition condition, int maxLength, Queue<String> data) {
        this.lock = lock;
        this.condition = condition;
        this.maxLength = maxLength;
        this.data = data;
    }

    @Override
    public void run() {
        int count = 0;
        while (true) {
            //加锁
            lock.lock();
            while (data.size() == maxLength) {
                System.out.println("生产者队列满了,等待");
                try {
                    //手动await进入等待队列,释放线程 相当于Synchronized的wait
                    condition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("生产者生产消息:" + (++count));
            data.add(String.valueOf(count));
            //唤醒其他线程等待线程 相当于Sychronized的notify
            condition.signal();
            //释放锁
            lock.unlock();
        }
    }
}


class Consumer implements Runnable {
    private Lock lock;
    private Condition condition;
    private int maxLength;
    private Queue<String> data;

    public Consumer(Lock lock, Condition condition, int maxLength, Queue<String> data) {
        this.lock = lock;
        this.condition = condition;
        this.maxLength = maxLength;
        this.data = data;
    }


    @Override
    public void run() {
        while (true) {
            lock.lock();
            while (data.size() == 0) {
                System.out.println("消费者队列空了,等待");
                try {
                    condition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("消费者消费消息:" + data.remove());
            condition.signal();
            lock.unlock();
        }
    }
}

核心流程

countDownLatch.await()
public final void await() throws InterruptedException {
    if (Thread.interrupted())
        throw new InterruptedException();
    //尝试加入到Condition单向链表
    Node node = addConditionWaiter();
    //释放当前重入锁 记录重入次数,再次被唤醒时需要重新写入重入次数 
    //里面执行了unparkSuccessor(h) 方法会唤醒AQS的head.next节点线程
    int savedState = fullyRelease(node);
    //记录中断类型的字段
    int interruptMode = 0;
    while (!isOnSyncQueue(node)) {
        //挂起线程
        LockSupport.park(this);
        if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
            break;
    }
    //通过singel方法node被转移到了AQS队列, 被唤醒之后需要将重入锁次数传入重新竞争锁
    if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
        interruptMode = REINTERRUPT;
    if (node.nextWaiter != null) // clean up if cancelled
        //清理cancelled状态的node
        unlinkCancelledWaiters();
    //根据中断标识 选择处理中断的方式(重新响应中断或者抛出interruptException异常)
    if (interruptMode != 0)
        reportInterruptAfterWait(interruptMode);
}

//加入单向Condition链表的方法
private Node addConditionWaiter() {
    Node t = lastWaiter;
    // If lastWaiter is cancelled, clean out.
    if (t != null && t.waitStatus != Node.CONDITION) {
        unlinkCancelledWaiters();
        t = lastWaiter;
    }
    Node node = new Node(Thread.currentThread(), Node.CONDITION);
    if (t == null)
        firstWaiter = node;
    else
        t.nextWaiter = node;
    lastWaiter = node;
    return node;
}

//判断节点是否在AQS队列 如果不在才需要park线程
final boolean isOnSyncQueue(Node node) {
    //标识node在Condition队列,不在AQS,需要park挂起当前node线程
    if (node.waitStatus == Node.CONDITION || node.prev == null)
        return false;
    //快捷判断 在AQS的方法 因为Condition队列只有nextWaiter的关系
    if (node.next != null) // If has successor, it must be on queue
        return true;
    /*
         * node.prev can be non-null, but not yet on queue because
         * the CAS to place it on queue can fail. So we have to
         * traverse from tail to make sure it actually made it.  It
         * will always be near the tail in calls to this method, and
         * unless the CAS failed (which is unlikely), it will be
         * there, so we hardly ever traverse much.
         */
    //上一步没有找到 就从AQS尾部查找node 判断是否在AQS
    return findNodeFromTail(node);
}



countDownLatch.single()
public final void signal() {
    if (!isHeldExclusively())
        throw new IllegalMonitorStateException();
    //将firstWaiter缓存到first局部变量
    Node first = firstWaiter;
    if (first != null)
        //唤醒first节点
        doSignal(first);
}

private void doSignal(Node first) {
    do {
        //firstWaiter = first.nextWaiter 将first.nextWaiter交给firstWaiter缓存
        //如果first的下一个节点为空,说明condition队列空了,设置lastWaiter==null 
        if ( (firstWaiter = first.nextWaiter) == null)
            lastWaiter = null;
        //唤醒first之前将first.nextWaiter==null,帮助first GC
        first.nextWaiter = null;
      //transferForSignal(first) 尝试将first转移动到AQS队列
        //(first = firstWaiter) != null 转移失败了,将first赋值为原来的first.nextWaiter,继续唤醒,知道唤醒一个有效对的Condition节点
    } while (!transferForSignal(first) &&
             (first = firstWaiter) != null);
}

//转移到AQS核心逻辑
final boolean transferForSignal(Node node) {
    /*
         * If cannot change waitStatus, the node has been cancelled.
         */
    //cas将节点的waitStatus从CONDITION-> node初始waitStatus:0
    if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
        //失败说明唤醒失败,抛弃该node唤醒,唤醒它的nextWaiter
        return false;

    /*
         * Splice onto queue and try to set waitStatus of predecessor to
         * indicate that thread is (probably) waiting. If cancelled or
         * attempt to set waitStatus fails, wake up to resync (in which
         * case the waitStatus can be transiently and harmlessly wrong).
         */
    //cas成功后 enq将node加入到AQS队列 返回node在AQS中的prev节点
    Node p = enq(node);
    //拿到prev节点的waitStatus
    int ws = p.waitStatus;
    //如果prev节点的waitStatus为cancelled后者修改为SINGEL失败,可以提前唤醒node的线程
    if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
        //提前唤醒node的线程,这是一种优化的方案,因为node迟早都要唤醒,虽然执行single的线程还没有挂起,但是唤醒之后反正要重新竞争锁不存在线程安全问题,并且如果prev节点是called状态,需要清理called需要时间,所以提前唤醒node,提升效率
        LockSupport.unpark(node.thread);
    //如果提前唤醒不满足条件,就会通过ReentrantLock自己的unlock方法,来唤醒AQS中的node
    return true;
}

//回到park被挂起位置

 public final void await() throws InterruptedException {
     if (Thread.interrupted())
         throw new InterruptedException();
     Node node = addConditionWaiter();
     long savedState = fullyRelease(node);
     int interruptMode = 0;
     while (!isOnSyncQueue(node)) {
         LockSupport.park(this);
         if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
             break;
     }
     //调用ReentrantLock的竞争锁方法 重新竞争锁资源
     if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
         interruptMode = REINTERRUPT;
     if (node.nextWaiter != null) // clean up if cancelled
         unlinkCancelledWaiters();
     if (interruptMode != 0)
         reportInterruptAfterWait(interruptMode);
 }
//这个又回到了ReentrantLock的了逻辑,竞争成功就替换head节点,不成功挂起线程
final boolean acquireQueued(final Node node, long arg) {
    boolean failed = true;
    try {
        boolean interrupted = false;
        for (;;) {
            final Node p = node.predecessor();
            if (p == head && tryAcquire(arg)) {
                setHead(node);
                p.next = null; // help GC
                failed = false;
                return interrupted;
            }
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt())
                interrupted = true;
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}



阻塞队列(Condition的一种应用场景)

阻塞队列利用了ReetrantLock,及其子下两个condition队列,NotFull存储生产者队列,NotEmpty存储消费者队列,实现消息的put和take的阻塞机制。

核心对象

  • NotFull: 存储生产者线程的Condition阻塞队列,当Producer调用put方法发现已经超过了队列最大容量是,会将线程缓存到NotFull
  • NotEmpty: 存储消费者线程的Condition阻塞队列,当Consumer调用take方法,发现队列里面没有数据,会将线程缓存到NotEmpty
  • putIndex: 记录生产者最后一次put到阻塞队列的下标位置,当达到最大下标=>重置为0
  • takeIndex: 记录消费者最后一次take那去数据的阻塞队列的下标位置,当达到最大下标=>重置为0

消息put到blockQueue里面,如果队列未满,加入到队列,同时putIndex++,当put到最大容量是,putIndex回到初始位置0;如果下次还有producer put消息,则将线程阻塞到NotFull的Condition队列

消费者从blockQueue中take拉取消息,如果队列中只有一个数据,消费完该数据之后,takeIndex回到初始位置0,如果还有消费者线程take消费,则线程阻塞到NotEmpty的Condition队列中。

示例代码

public class BlockQueueDemo {
    public static void main(String[] args) {
        ArrayBlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(10);
        //消费者线程
        new Thread(() -> {
            try {
                while (true) {
                    Thread.sleep(1000);
                    //如果线程空了 take方法会使线程挂起
                    String data = blockingQueue.take();
                    System.out.println("开始消费消息:" + data);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
        //生产者线程
        new Thread(() -> {
            while (true) {
                int count = 0;
                try {
                    System.out.println("生产消息:" + (++count));
                    //如果队列满了 put方法会使当前线程挂起
                    blockingQueue.put(String.valueOf(count));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}

image-20210705192639898

CountDownLatch

countDownLatch相当于提供一个阀门,在初始化的时候设置一个state=n,每次在执行countDownLatch.countDown()->n--;当n==0时,所有的调用countDownLatch.await();的方法就都会执行。

类图

image-20210705234913249

核心对象

  • CountDownLatch 类本身
  • Sync CountDownLatch的内部类(不要混淆 ReentrantLock中也有一个Sync内部类)
  • AbstractQueueSynchorized AQS队列里面 里面维护了双向链表和单向链表

代码示例

public class CountDownLachDemo{
    public static void main(String[] args) {
        CountDownLatch countDownLatch = new CountDownLatch(1);
        for (int i=0;i<1000;i++) {
            new Thread(() -> {
                try {
                    countDownLatch.await();
                    System.out.println(Thread.currentThread().getName() + "运行");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            },"Thread_" + i).start();
        }
        System.out.println("3秒后开启阀门");
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        countDownLatch.countDown();
    }
}

核心流程

new CountDownLatch

//new CountDownLatch 传入的参数最终会设置到AQS的state
protected final void setState(int newState) {
    state = newState;
}

await

public void await() throws InterruptedException {
    sync.acquireSharedInterruptibly(1);
}

public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
    if (Thread.interrupted())
        throw new InterruptedException();
    //tryAcquireShare 判断state是否==0,满足返回1 否则返回-1
    if (tryAcquireShared(arg) < 0)
        //加入到单向链表 阻塞线程
        doAcquireSharedInterruptibly(arg);
}
//tryAcquireShare 判断state是否==0,满足返回1 否则返回-1
protected int tryAcquireShared(int acquires) {
    return (getState() == 0) ? 1 : -1;
}

//加入到单向链表阻塞线程
private void doAcquireSharedInterruptibly(int arg)
    throws InterruptedException {
    //加入双向链表 并将nextWaiter标记为Node.SHARED
    final Node node = addWaiter(Node.SHARED);
    boolean failed = true;
    try {
        for (;;) {
            //判断node的上一个节点是不是头节点
            final Node p = node.predecessor();
            if (p == head) {
                //是重新判断state  (getState() == 0) ? 1 : -1;
                int r = tryAcquireShared(arg);
                if (r >= 0) {
                    //state=0设置当前node为头节点,并唤醒下一个节点 next
                    setHeadAndPropagate(node, r);
                    p.next = null; // help GC
                    failed = false;
                    return;
                }
            }
            //没有获取到节点则 执行parkAndCheckInterrupt 
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt())
                //parkAndCheckInterrupt会返回是否被中断标识并复位 -> 此处如果有被中断则				响应中断抛出异常
                throw new InterruptedException();
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}

countDown

public void countDown() {
    sync.releaseShared(1);
}
public final boolean releaseShared(int arg) {
    //tryReleaseShared 如果state在执行减法操作后==0 
    //就会触发doReleaseSharedunpark阻塞的线程
    if (tryReleaseShared(arg)) {
        //unpark阻塞队列的线程
        doReleaseShared();
        return true;
    }
    return false;
}

protected boolean tryReleaseShared(int releases) {
    // Decrement count; signal when transition to zero
    for (;;) {
        int c = getState();
        //如果本来就是0 说明已经执行过doReleaseShared 不需要重复执行 返回false
        if (c == 0)
            return false;
        int nextc = c-1;
        //减法操作后 结果==0 说明countDownlatch需要unpark在awaid方法阻塞的线程
        if (compareAndSetState(c, nextc))
            return nextc == 0;
    }
}


重要方法唤醒AQS队列的线程

private void doReleaseShared() {
    /*
         * Ensure that a release propagates, even if there are other
         * in-progress acquires/releases.  This proceeds in the usual
         * way of trying to unparkSuccessor of head if it needs
         * signal. But if it does not, status is set to PROPAGATE to
         * ensure that upon release, propagation continues.
         * Additionally, we must loop in case a new node is added
         * while we are doing this. Also, unlike other uses of
         * unparkSuccessor, we need to know if CAS to reset status
         * fails, if so rechecking.
         */
    for (;;) {
        Node h = head;
        if (h != null && h != tail) {
            int ws = h.waitStatus;
            if (ws == Node.SIGNAL) {
                if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
                    continue;            // loop to recheck cases
                //唤醒head节点的下一个节点
                unparkSuccessor(h);
            }
            else if (ws == 0 &&
                     !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
                continue;                // loop on failed CAS
        }
        if (h == head)                   // loop if head changed
            break;
    }
}

//唤醒之后的逻辑

private void doAcquireSharedInterruptibly(int arg)
    throws InterruptedException {
    final Node node = addWaiter(Node.SHARED);
    boolean failed = true;
    try {
        for (;;) {
            final Node p = node.predecessor();
            //唤醒后自旋进入方法判断 上一个节点是不是头节点
            if (p == head) {
                //是重新判断state  (getState() == 0) ? 1 : -1; 判断是否已完全释放门栓锁
                int r = tryAcquireShared(arg);
                if (r >= 0) {
                    //state=0设置当前node为头节点,并唤醒下一个节点 next
                    setHeadAndPropagate(node, r);
                    p.next = null; // help GC
                    failed = false;
                    return;
                }
            }
            //没有获取到节点则 执行parkAndCheckInterrupt 
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt())
                // !!!从这里开始唤醒之后的逻辑
                //parkAndCheckInterrupt会返回是否被中断标识并复位 -> 此处如果有被中断则				响应中断抛出异常
                throw new InterruptedException();
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}
//再次调回doReleaseShared唤醒下一个节点
private void setHeadAndPropagate(Node node, int propagate) {
        Node h = head; // Record old head for check below
    	//将当前唤醒的节点设置为新的head节点
        setHead(node);
        /*
         * Try to signal next queued node if:
         *   Propagation was indicated by caller,
         *     or was recorded (as h.waitStatus either before
         *     or after setHead) by a previous operation
         *     (note: this uses sign-check of waitStatus because
         *      PROPAGATE status may transition to SIGNAL.)
         * and
         *   The next node is waiting in shared mode,
         *     or we don't know, because it appears null
         *
         * The conservatism in both of these checks may cause
         * unnecessary wake-ups, but only when there are multiple
         * racing acquires/releases, so most need signals now or soon
         * anyway.
         */
        if (propagate > 0 || h == null || h.waitStatus < 0 ||
            (h = head) == null || h.waitStatus < 0) {
            //拿到下一个节点 不为空就唤醒
            Node s = node.next;
            if (s == null || s.isShared())
                //唤醒head节点的下一个节点
                doReleaseShared();
        }
    }
//通过传递唤醒最终就唤醒了所有的线程

Semaphore

Semaphore 信号量,是限流常用的实现方式。类似于停车位,想像一下现在只有5个停车位,只能同时有5辆车停车,其他车需要等待释放信号量也就是车位空闲出来,才能停车。

public class SemaphoreDemo {
    public static void main(String[] args) {
        //建立信号量
        Semaphore semaphore = new Semaphore(5);
        for(int i=0;i<1000;i++){
            new Thread(
                    () -> {
                        try {
                            semaphore.acquire();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        try {
                            Thread.sleep(3000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName() + "开始运行");
                        semaphore.release();
                    } , "Thread_" + i
            ).start();
        }

    }
}

Semaphore和CounDownLatch实现几乎一样,只是tryAcquireShared获取执行权限的方法不一样

 public final void acquireSharedInterruptibly(int arg)
     throws InterruptedException {
     if (Thread.interrupted())
         throw new InterruptedException();
     if (tryAcquireShared(arg) < 0)
         doAcquireSharedInterruptibly(arg);
 }

final int nonfairTryAcquireShared(int acquires) {
    for (;;) {
        int available = getState();
        //每次回用存量的信号量值 - 传入的需要获取值
        int remaining = available - acquires;
        //如果小于0 就阻塞进入if逻辑 如果>0说明有执行权限直接返回不处理
        if (remaining < 0 ||
            compareAndSetState(available, remaining))
            return remaining;
    }
}


private void doAcquireSharedInterruptibly(int arg)
        throws InterruptedException {
        final Node node = addWaiter(Node.SHARED);
        boolean failed = true;
        try {
            for (;;) {
                final Node p = node.predecessor();
                if (p == head) {
                    //这里由于是减法之后大于0才会触发setHeadAndPropagate
                    //所以它的传递唤醒,只能在state>0的情况下生效
                    //不会一直传递唤醒下去 这是和countDownLatch最大的区别
                    int r = tryAcquireShared(arg);
                    if (r >= 0) {
                        setHeadAndPropagate(node, r);
                        p.next = null; // help GC
                        failed = false;
                        return;
                    }
                }
                //state减法之后<0说明信号量值用完,需要等待其他线程释放信号,挂起线程
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    throw new InterruptedException();
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

posted @ 2021-07-06 15:42  醉梦了红尘  阅读(173)  评论(0)    收藏  举报