侧边栏壁纸
博主头像
再见理想博主等级

只争朝夕,不负韶华

  • 累计撰写 112 篇文章
  • 累计创建 64 个标签
  • 累计收到 4 条评论

目 录CONTENT

文章目录

CountDownLatch 倒计时器

再见理想
2022-05-29 / 0 评论 / 0 点赞 / 396 阅读 / 645 字

一,前言

CountDownLatch 是一个非常实用的多线程控制工具类。“Count Down”在英文中意为倒计数, Latch为门闩的意思。简单地称之为倒计数器,这个工具通常用来控制线程等待,它可以让某一个线程等待直到倒计时结束,再开始执行。

CountDownLatch 的构造函数接收一个整数作为参数,即当前这个计数器的计数个数。

public CountDownLatch(int count)

二,构造函数

public CountDownLatch(int count) {
        if (count < 0) throw new IllegalArgumentException("count < 0");
        this.sync = new Sync(count);
}

创建一个参数为 count 的 Sync 对象,看看 Sync 代码:

private static final class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = 4982264981922014374L;

        Sync(int count) {
            setState(count);
        }

        int getCount() {
            return getState();
        }

        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();
                if (c == 0)
                    return false;
                int nextc = c-1;
                if (compareAndSetState(c, nextc))
                    return nextc == 0;
            }
        }
    }

可以看到,Sync(int count) 构造函数中,默认加上了 count 把锁!

三,源码

await()

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

可见,底层使用了 AQS 的 acquireSharedInterruptibly 方法 进行获取共享锁!由于创建 CountDownLatch 对象时已经加上了 count 把锁,通过 await() 方法阻塞在等待队列尾部。等待 state = 0 锁释放完,再去获取锁。

countDown()

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

可见,底层使用了 AQS 的 releaseShared 方法释放一把共享锁。

四,简单使用

import java.util.concurrent.*;

public class CountDownLatchDemo implements Runnable {

    private static final CountDownLatch latch = new CountDownLatch(10);
    private static final CountDownLatchDemo demo = new CountDownLatchDemo();

    public static void main(String[] args) throws InterruptedException {
        ExecutorService exec = Executors.newFixedThreadPool(10);
        for (int i = 0; i < 10; i++) {
            Thread.sleep(100);
			// 执行子线程 计数-1
            exec.submit(demo);
        }

        // 等待检查
        latch.await();
        // 倒计时结束后再继续执行
        System.out.println("go on..." + ":线程:" + Thread.currentThread().getName());
		// 关闭线程池
        exec.shutdown();
    }

    @Override
    public void run() {
        System.out.println("checking...倒计时:" + latch.getCount() + ":线程:" + Thread.currentThread().getName());
		// 计数-1
        latch.countDown();
    }
}

执行结果:

checking...倒计时:10:线程:pool-1-thread-1
checking...倒计时:9:线程:pool-1-thread-2
checking...倒计时:8:线程:pool-1-thread-3
checking...倒计时:7:线程:pool-1-thread-4
checking...倒计时:6:线程:pool-1-thread-5
checking...倒计时:5:线程:pool-1-thread-6
checking...倒计时:4:线程:pool-1-thread-7
checking...倒计时:3:线程:pool-1-thread-8
checking...倒计时:2:线程:pool-1-thread-9
checking...倒计时:1:线程:pool-1-thread-10
go on...:线程:main
0

评论区