1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
|
import
java.util.concurrent.CountDownLatch;
/**
* create at 11-9-17
*
* @author KETQI
* @category CountDownLatch主要起倒計時計數器做用,它主要有兩個方法await()和countDown()。
* 一旦某個線程調用await()方法,那麼該線程就會阻塞,等待CountDownLatch計數器倒計時歸零,
* 須要注意的是儘管線程調用await()方法後會阻塞,
* 可是CountDownLatch容許別的線程調用countDown()方法,將計數器減一。
* 也就是說調用計時器的線程阻塞後,能夠利用別的線程控制調用線程什麼時候重新開始運行。
* <p/>
* 該demo主要想要作的事就是:在主線程中建立N個子線程,讓支線程等待主線程將開關計數器startSignal打開。
* 而當主線程打開startSignal開關後,主線程要等待計數器doneSignal歸零,
* 而doneSignal計數器歸零依賴於每一個支線程爲主線程的計數器減一。
* 因此當主線程打開開關後,支線程才能運行完畢,而只有支線程所有運行完畢,才能打開主線程的計數器。
* 這樣整個程序才能走完
*/
public
class
CountDownLatchDemo {
public
static
final
int
N =
5
;
public
static
void
main(String[] args)
throws
InterruptedException {
// 用於向工做線程發送啓動信號,由主線程調用
CountDownLatch startSignal =
new
CountDownLatch(
1
);
// 用於等待工做線程的結束信號,由子線程調用
CountDownLatch doneSignal =
new
CountDownLatch(N);
// 建立啓動線程
System.out.println(
"開始建立並運行分支線程,且分支線程啓動startSignal計數器,等待主線程將startSignal計數器打開"
);
for
(
int
i =
0
; i < N; i++) {
new
Thread(
new
LatchWorker(startSignal, doneSignal),
"t"
+ i).start();
}
// 主線程,遞減開始計數器,讓全部線程開始工做
System.out.println(
"主線程"
+ Thread.currentThread().getName() +
"將startSignal計數器打開"
);
startSignal.countDown();
// 主線程阻塞,等待全部線程完成
System.out.println(
"主線程"
+ Thread.currentThread().getName() +
"開始倒計時5個數"
);
doneSignal.await();
/**
* 爲何說運行到下一句,全部線程就所有運行完畢了呢。 由於主線程要倒計時5個數, 而產生的5個支線程在運行完畢前會將主線程的計數器減一,
* 因此若是全部支線程運行完畢了 ,主線程才能繼續運行主線程的最後一個打印程序
*/
System.out.println(
"全部線程運行完畢"
);
}
}
class
LatchWorker
implements
Runnable {
// 用於等待啓動信號
private
final
CountDownLatch startSignal;
// 用於發送結束信號
private
final
CountDownLatch doneSignal;
LatchWorker(CountDownLatch startSignal, CountDownLatch doneSignal) {
this
.startSignal = startSignal;
this
.doneSignal = doneSignal;
}
public
void
run() {
try
{
// 一旦調用await()方法,該線程就會開始阻塞。知道計數器startSignal爲0
System.out.println(Thread.currentThread().getName() +
" 開始調用await()方法,等待計數器startSignal被主線程打開"
);
startSignal.await();
doWork();
System.out.println(Thread.currentThread().getName() +
" 將主線程的計數器減一"
);
doneSignal.countDown();
// 發送完成信號
}
catch
(InterruptedException ex) {
ex.printStackTrace();
}
}
void
doWork() {
System.out.println(Thread.currentThread().getName() +
" 的計數器被打開,分支線程開始運行"
);
try
{
Thread.sleep((
long
) Math.random() *
10000
);
}
catch
(InterruptedException e) {
e.printStackTrace();
}
}
}
|