Java併發編程之CountDownLatch

先來了解一下其原理

from when and where:

CountDownLatch是在java1.5被引入的,跟它一起被引入的併發工具類還有CyclicBarrier、Semaphore、ConcurrentHashMap和BlockingQueue,它們都存在於java.util.concurrent包下。

introduce:

CountDownLatch這個類能夠使一個線程等待其他線程完成各自的工作後再執行。例如,應用程序的主線程希望在負責啟動框架服務的線程已經啟動所有的框架服務之後再執行。

function:

CountDownLatch是通過一個計數器來實現的,計數器的初始值為線程的數量。每當一個線程完成了自己的任務後,計數器的值就會減1。當計數器值到達0時,它表示所有的線程已經完成了任務,然後在閉鎖上等待的線程就可以恢復執行任務。

Java併發編程之CountDownLatch

doc:

https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CountDownLatch.html

application:

step 1:

構造器中的計數值(count)實際上就是閉鎖需要等待的線程數量。這個值只能被設置一次,而且CountDownLatch沒有提供任何機制去重新設置這個計數值

step 2:

與CountDownLatch的第一次交互是主線程等待其他線程。主線程必須在啟動其他線程後立即調用CountDownLatch.await()方法。這樣主線程的操作就會在這個方法上阻塞,直到其他線程完成各自的任務。

step 3:

其他N 個線程必須引用閉鎖對象,因為他們需要通知CountDownLatch對象,他們已經完成了各自的任務。這種通知機制是通過

CountDownLatch.countDown()方法來完成的;每調用一次這個方法,在構造函數中初始化的count值就減1。所以當N個線程都調 用了這個方法,count的值等於0,然後主線程就能通過await()方法,恢復執行自己的任務。

鏈接上一篇文章線程之間的通信(對象鎖的await()與notify()方式實現):https://www.toutiao.com/i6619537172238172676/

做一下對比

下面上代碼

package com.bjsxt.base.conn008;

import java.util.ArrayList;

import java.util.List;

import java.util.concurrent.CountDownLatch;

/**

* @author zz

*

*/

public class ListAdd2 {

private volatile static List list = new ArrayList();

public void add(){

list.add("bjsxt");

}

public int size(){

return list.size();

}

public static void main(String[] args) {

final ListAdd2 list2 = new ListAdd2();

//final Object lock = new Object();

//

CountDownLatch countDownLatch = new CountDownLatch(1);

Thread t1 = new Thread(new Runnable() {

@Override

public void run() {

try {

// synchronized (lock) {

System.out.println("t1啟動..");

for(int i = 0; i <10; i++){

list2.add();

System.out.println("當前線程:" + Thread.currentThread().getName() + "添加了一個元素..");

Thread.sleep(500);

if(list2.size() == 5){

System.out.println("已經發出通知..");

//計數器減1

countDownLatch.countDown();

// lock.notify();

// }

}

}

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}, "t1");

Thread t2 = new Thread(new Runnable() {

@Override

public void run() {

// synchronized (lock) {

System.out.println("t2啟動..");

if(list2.size() != 5){

try {

// lock.wait();

//

countDownLatch.await();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

System.out.println("當前線程:" + Thread.currentThread().getName() + "收到通知線程停止..");

throw new RuntimeException();

// }

}

}, "t2");

t2.start();

t1.start();

}

}

運行結果解析

Java併發編程之CountDownLatch

提示:CountDownLatch可以靈活的運用,你可以使用多個CountDownLatch實例對象靈活的使用在你的多線程執行時的業務判斷中

CountDownLatch c1 = new CountDownLatch(1);

CountDownLatch c2 = new CountDownLatch(2);

CountDownLatch cn = new CountDownLatch(N);

總之,當c1.await()中c1.countDown()後計數器為0時,當前線程就會繼續執行了,是不是很方便

import java.util.concurrent.CountDownLatch;

/**
* 示例:CountDownLatch的使用舉例 Mail: [email protected]
* 等待所有的線程都執行完成後,再執行下面的步驟
*
* @author janeky
*/
public class TestCountDownLatch {
private static final int N = 10;

public static void main(String[] args) throws InterruptedException {
CountDownLatch doneSignal = new CountDownLatch(N);//N為要控制的線程的數量
CountDownLatch startSignal = new CountDownLatch(1);// 開始執行信號

for (int i = 1; i <= N; i++) {
new Thread(new Worker(i, doneSignal, startSignal)).start();// 線程啟動了
}
System.out.println("begin------------");
startSignal.countDown();// 開始執行啦

doneSignal.await();// 等待所有的線程執行完畢,在所有線程未執行完成之前(doneSignal.getCount()>0),await()方法會受阻

System.out.println("Ok");

}

static class Worker implements Runnable {
private final CountDownLatch doneSignal;
private final CountDownLatch startSignal;
private int beginIndex;

Worker(int beginIndex, CountDownLatch doneSignal,
CountDownLatch startSignal) {
this.startSignal = startSignal;
this.beginIndex = beginIndex;
this.doneSignal = doneSignal;
}

public void run() {
try {
startSignal.await(); // 等待開始執行信號的發佈
beginIndex = (beginIndex - 1) * 10 + 1;
for (int i = beginIndex; i <= beginIndex + 10; i++) {
System.out.println(i);
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("done Count"+doneSignal.getCount());
doneSignal.countDown();//表示一個線程執行完成
System.out.println("colsed done Count"+doneSignal.getCount());
}
}
}
}


分享到:


相關文章: