java并发工具CountDownLatch的理解以及使用

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/asdasd3418/article/details/77172473

最近在准备面试,所以临时抱抱佛脚,翻翻之前的学习笔记,对java多线程有了进一步的了解。还真是应了那句话:“书读百遍,其义自见”。废话不多说,说说我对CountDownLatch的一些理解。

1.CountDownLatch是干嘛的

CountDownLatch是JAVA提供在java.util.concurrent包下的一个辅助类,可以把它看成是一个计数器,其内部维护着一个count计数,只不过对这个计数器的操作都是原子操作,同时只能有一个线程去操作这个计数器,CountDownLatch通过构造函数传入一个初始计数值,调用者可以通过调用CounDownLatch对象的cutDown()方法,来使计数减1;如果调用对象上的await()方法,那么调用者就会一直阻塞在这里,直到别人通过cutDown方法,将计数减到0,才可以继续执行。

A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.

A CountDownLatch is initialized with a givencount. The await methods block until the current count reaches zero due to invocations of thecountDown method, after which all waiting threads are released and any subsequent invocations ofawait return immediately. This is a one-shot phenomenon -- the count cannot be reset. If you need a version that resets the count, consider using aCyclicBarrier.

A CountDownLatch is a versatile synchronization tool and can be used for a number of purposes. ACountDownLatch initialized with a count of one serves as a simple on/off latch, or gate: all threads invokingawait wait at the gate until it is opened by a thread invokingcountDown. A CountDownLatch initialized toN can be used to make one thread wait until N threads have completed some action, or some action has been completed N times.

A useful property of a CountDownLatch is that it doesn't require that threads callingcountDown wait for the count to reach zero before proceeding, it simply prevents any thread from proceeding past anawait until all threads could pass. 

以上是jdk的官方解释,同时doc里也给了相应的例子。

2.CountDownLatch怎么用

这里我举个简单的例子,假如有5个运动员赛跑,为了公平所有运动员需要同时起跑。同时,当最后一个运动员跑完之后,比赛结束。怎么用线程模拟呢?我们假设每个运动员是一个线程,然后只需要通过CountDownLatch就可以简单的实现这个问题。

	public static void main(String[] args) {
		
		//所有线程阻塞,然后统一开始
		CountDownLatch begin = new CountDownLatch(1);
		
		//主线程阻塞,直到所有分线程执行完毕
		CountDownLatch end = new CountDownLatch(5);
		
		for(int i = 0; i < 5; i++){
			Thread thread = new Thread(new Runnable() {
				
				@Override
				public void run() {
					try {
						begin.await();
						System.out.println(Thread.currentThread().getName() + " 起跑");
						Thread.sleep(1000);
						System.out.println(Thread.currentThread().getName() + " 到达终点");
						end.countDown();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					
				}
			});
			
			thread.start();
		}
		
		try {
			System.out.println("1秒后统一开始");
			Thread.sleep(1000);
			begin.countDown();

			end.await();
			System.out.println("停止比赛");
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
	}

以下是运行结果:

1秒后统一开始
Thread-1 起跑
Thread-4 起跑
Thread-3 起跑
Thread-0 起跑
Thread-2 起跑
Thread-3 到达终点
Thread-0 到达终点
Thread-4 到达终点
Thread-1 到达终点
Thread-2 到达终点
停止比赛

可以看出,分线程通过第一个CountDownLatch实现了阻塞,直到主线程调用了countDown()方法,所有分线程才继续执行。

然后主线程通过第二个CountDownLatch实现阻塞,直到所有分线程都调用了countDown()方法。

3.CountDownLatch的使用场景

  • 确保某个计算在其需要的所有资源都被初始化之后才继续执行。
  • 确保某个服务在其依赖的所有其他服务都已启动后才启动。
  • 等待知道某个操作的所有者都就绪在继续执行。

4.CountDownLatch源码分析

    public void await() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }
    public void countDown() {
        sync.releaseShared(1);
    }
可以看出CountDownLatch的两个主要方法都是通过sync这个属性来实现的,而Sync是aqs的一个子类,如下:
/**
     * Synchronization control For CountDownLatch.
     * Uses AQS state to represent count.
     */
    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;
            }
        }
    }
具体aqs的相关知识,这里就不再细讲。

以上就是我关于CountDownLatch的理解。

参考:java并发编程实战。


展开阅读全文

没有更多推荐了,返回首页