CountDownLatch学习笔记

概念:CountDownLatch允许一个或者多个线程等待其他线程完成操作。

CountDownLatch主要方法:

await() 使当前线程进入等待队列等待,当latch减为0或中断时,线程被唤醒。

await(long timeout, TimeUnit unit) 设置超时时间。

countDown() 使latch值减1,为0时唤醒。

getCount() 获取latch值。

 CountDownLatch简单使用:


package com.Test;

/*
作者:阳小江
 */
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.ReentrantLock;

public class Cas {

    public static void main(String [] args)throws InterruptedException{
        CountDownLatch count=new CountDownLatch(3);

        WaitThread waitThread1=new WaitThread("等待线程1",count);
        WaitThread waitThread2=new WaitThread("等待线程2",count);

        Worker worker1=new Worker("工作线程1",count);
        Worker worker2=new Worker("工作线程2",count);
        Worker worker3=new Worker("工作线程3",count);



        waitThread1.start();
        waitThread2.start();
        Thread.sleep(1000);
        worker1.start();
        worker2.start();
        worker3.start();
    }


}
class WaitThread extends Thread{
    private  String name;
    private  CountDownLatch count;

    public WaitThread(String name,CountDownLatch count){
        this.count=count;
        this.name=name;
    }

    @Override
    public void run() {
        try {
            System.out.println(this.name+"等待中");
            count.await();
            System.out.println(this.name+"运行");
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}
class  Worker  extends Thread {
    private  String name;
    private  CountDownLatch count;
    public Worker(String name,CountDownLatch count){
        this.count=count;
        this.name=name;
    }

    @Override
    public void run() {
        System.out.println(this.name+"开始运行");
        try {
            Thread.sleep(2);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
        System.out.println(this.name+"运行结束");
        count.countDown();
    }
}

结果:

查看源码后理解:

CountDownLatch通过内部类Sync来实现同步

Sync继承AQS

其中 tryAcquireSharedtryReleaseShared 分别为获取和释放同步状态

源码如下:

`  
 protected int tryAcquireShared(int acquires) {          
  return (getState() == 0) ? 1 : -1;        }

protected boolean tryReleaseShared(int releases) {
            // Decrement count; signal when transition to zero
            for (;;) {
                int c = getState();
                // 如果同步状态的值已经是0了,不要再释放同步状态了,也不要减1了
                if (c == 0)
                    return false;
                // 减1
                int nextc = c - 1;
                if (compareAndSetState(c, nextc))
                    return nextc == 0;
            }
        }

await()

源码中首先调用AQS的acquireSharedInterruptibly(int arg)方法

判断是否被中断,否则 尝试获取同步状态,

   protected int tryAcquireShared(int acquires) {   
         return (getState() == 0) ? 1 : -1;      }

State为0,则获取成功。

否则通过自旋AQS 的 docquireSharedInterruptibly(int arg) 挂起

将线程加入队列的尾部,然后自旋判断该节点前一个节点是否为头节点,是则尝试获取同步状态,成功则设置该节点为头节点,

前一个节点不是头节点则挂起。

countDown()

   
 public void countDown() {
        sync.releaseShared(1);
    }
调用AQS的releaseShared(1)方法

   public final boolean releaseShared(int arg) {
        // 尝试释放同步状态
        if (tryReleaseShared(arg)) {
            // 如果成功,进入自旋,尝试唤醒同步队列中头结点的后继节点
            doReleaseShared();
            return true;
        }
        return false;
    }
​
成功后调用doReleaseShared()方法,获取头节点的状态,不为空且为SIGBNAL 通过unparSUccessor()方法唤醒后续节点。

释放所有调用await()等待的线程

唤醒一个节点时,设置该节点为头节点,获取该节点下一个节点,调用doReleaseShare()唤醒线程,唤醒后设置为头节点。

 if (h == head)
                break;
        }

每次循环后判断head头节点是否改变,没有则退出循环。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值