AQS之CountDownLatch 倒计数器

本文介绍了如何使用CountDownLatch实现线程间的等待与协作,通过示例展示了CountDownLatch在多线程场景的应用。同时,讨论了使用Synchronized关键字自定义同步器来实现类似的功能,并对比了CountDownLatch与自定义同步器的实现方式。文章最后总结了ReentrantLock、Semaphore和CountDownLatch在AQS中state变量的含义,强调了它们在并发控制中的不同用途。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

用法理解

呃, 这个类的作用就是 让线程 等待别的线程走完之后自己在执行。比如有个需求 线程A、B要等待线程C、D、E执行完,才能继续往下走。

public class TestCountDownLatch {
    public static void main(String[] args) {
        CountDownLatch countDownLatch = new CountDownLatch(3);
        new Thread(()->{
            try {
                System.out.println(Thread.currentThread().getName() + " 等待");
                countDownLatch.await();
                System.out.println(Thread.currentThread().getName() + "执行完毕");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "A").start();
        
        new Thread(()->{
            try {
                System.out.println(Thread.currentThread().getName() + " 等待");
                countDownLatch.await();
                System.out.println(Thread.currentThread().getName() + "执行完毕");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "B").start();

        new Thread(()->{
            try {
                System.out.println(Thread.currentThread().getName() + "开始执行");
                TimeUnit.SECONDS.sleep(1);
                System.out.println(Thread.currentThread().getName() + "执行完毕");
                countDownLatch.countDown();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "C").start();

        new Thread(()->{
            try {
                System.out.println(Thread.currentThread().getName() + "开始执行");
                TimeUnit.SECONDS.sleep(2);
                System.out.println(Thread.currentThread().getName() + "执行完毕");
                countDownLatch.countDown();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "D").start();

        new Thread(()->{
            try {
                System.out.println(Thread.currentThread().getName() + "开始执行");
                TimeUnit.SECONDS.sleep(3);
                System.out.println(Thread.currentThread().getName() + "执行完毕");
                countDownLatch.countDown();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "E").start();
    }
}


A 等待
B 等待
C开始执行
D开始执行
E开始执行
C执行完毕
D执行完毕
E执行完毕
A执行完毕
B执行完毕

Process finished with exit code 0

呃, 所以锁CountDownLatch还是挺好用的。

使用Synchronized实现CounDownLatch

设计思路:
使用一个变量记录倒计数
countDown 使得倒计数减少1,如果为0就notifayALL
await 如果倒计数不为0就wait

public class SynchronizedCountDownLatch {
    private int count = 0;
    private Object moniter = new Object();

    public SynchronizedCountDownLatch(int count) {
        this.count = count;
    }
    
    public void countDown(){
        synchronized (moniter){
            count--;
            if (count == 0){
                moniter.notifyAll();
            }
        }
    }
    
    public void await(){
        synchronized (moniter){
            while (count != 0){
                try {
                    moniter.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
}

使用AQS实现CounDownLatch

public class AqsCountDown {

    private Sync sync;

    public AqsCountDown(int count) {
        sync = new Sync(count);
    }

    private static class Sync extends MyAbstractQueueSynchronizer {
        public Sync(int count) {
            setState(count);
        }


        @Override
        protected int tryAquireShared(int premits) {
            int state = getState();
            if (state > 0) {
                return -1;
            }
            return 1;
        }

        @Override
        protected boolean tryReleaseShared(int i) {
            int state = getState();
            int update = state - i;
            if (update < 0) {
                throw new IllegalMonitorStateException();
            }
            while (true) {
                if (compareAndSetState(state, update)) {
                    break;
                }
                state = getState();
                update = state - i;
            }
            if (getState() == 0) {
                return true;
            } else {
                return false;
            }
        }
    }

    public void countDown() {
        sync.releaseShared();
    }

    public void await() {
        sync.acquireShared(1);
    }
}

总结

呃, CountDownLatch 思想挺好的。 需要注意区分ReentranctLock、Semaphore、CountDownLatch 三者 使用AQS state变量的含义

呃:
ReenTrantLock: state代表一把锁。
Semaphore: state 代表 n把锁。
CountDownLatch: state代表n个标记数 为1把锁

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值