Skip to content

Commit b5e646e

Browse files
committed
📝 Writing docs.
1 parent ed0f9fe commit b5e646e

2 files changed

Lines changed: 264 additions & 0 deletions

File tree

Lines changed: 263 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,263 @@
1+
---
2+
title: Java并发工具类
3+
date: 2018/05/15
4+
categories:
5+
- javase
6+
tags:
7+
- javase
8+
- concurrent
9+
- juc
10+
---
11+
12+
# Java 并发工具类
13+
14+
> 本文内容基于 JDK1.8。
15+
16+
<!-- TOC depthFrom:2 depthTo:3 -->
17+
18+
- [CountDownLatch](#countdownlatch)
19+
- [要点](#要点)
20+
- [源码](#源码)
21+
- [示例](#示例)
22+
- [CyclicBarrier](#cyclicbarrier)
23+
- [要点](#要点-1)
24+
- [源码](#源码-1)
25+
- [示例](#示例-1)
26+
- [Semaphore](#semaphore)
27+
- [要点](#要点-2)
28+
- [源码](#源码-2)
29+
- [示例](#示例-2)
30+
- [资料](#资料)
31+
32+
<!-- /TOC -->
33+
34+
JDK 的 `java.util.concurrent` 包(即 juc)中提供了几个非常有用的并发工具类。
35+
36+
## CountDownLatch
37+
38+
### 要点
39+
40+
* 作用:允许一个或多个线程等待,直到在其他线程中执行的一组操作完成。
41+
* 原理:`CountDownLatch` 维护一个计数器 count。每次调用 `countDown` 方法会让 count 的值减 1,减到 0 的时候,那些因为调用 `await` 方法而在等待的线程就会被唤醒。
42+
43+
<p align="center">
44+
<img src="https://raw.githubusercontent.com/dunwu/javase-notes/master/images/concurrent/CountdownLatch.png" alt="CountdownLatch">
45+
</p>
46+
47+
### 源码
48+
49+
`CountDownLatch` 唯一的构造器:
50+
51+
```java
52+
// 初始化计数器
53+
public CountDownLatch(int count) {};
54+
```
55+
56+
`CountDownLatch` 的重要方法:
57+
58+
```java
59+
// 调用 await() 方法的线程会被挂起,它会等待直到 count 值为 0 才继续执行
60+
public void await() throws InterruptedException { };
61+
// 和 await() 类似,只不过等待一定的时间后 count 值还没变为 0 的话就会继续执行
62+
public boolean await(long timeout, TimeUnit unit) throws InterruptedException { };
63+
// count 减 1
64+
public void countDown() { };
65+
```
66+
67+
### 示例
68+
69+
```java
70+
public class CountDownLatchDemo {
71+
72+
public static void main(String[] args) {
73+
final CountDownLatch latch = new CountDownLatch(2);
74+
75+
new Thread(() -> {
76+
try {
77+
System.out.println("子线程" + Thread.currentThread().getName() + "正在执行");
78+
Thread.sleep(3000);
79+
System.out.println("子线程" + Thread.currentThread().getName() + "执行完毕");
80+
latch.countDown();
81+
} catch (InterruptedException e) {
82+
e.printStackTrace();
83+
}
84+
}).start();
85+
86+
new Thread(() -> {
87+
try {
88+
System.out.println("子线程" + Thread.currentThread().getName() + "正在执行");
89+
Thread.sleep(3000);
90+
System.out.println("子线程" + Thread.currentThread().getName() + "执行完毕");
91+
latch.countDown();
92+
} catch (InterruptedException e) {
93+
e.printStackTrace();
94+
}
95+
}).start();
96+
97+
try {
98+
System.out.println("等待2个子线程执行完毕...");
99+
latch.await();
100+
System.out.println("2个子线程已经执行完毕");
101+
System.out.println("继续执行主线程");
102+
} catch (InterruptedException e) {
103+
e.printStackTrace();
104+
}
105+
}
106+
}
107+
```
108+
109+
## CyclicBarrier
110+
111+
### 要点
112+
113+
* 作用:字面意思回环栅栏,通过它可以实现让一组线程等待至某个状态之后再全部同时执行。叫做回环是因为当所有等待线程都被释放以后,`CyclicBarrier` 可以被重用。
114+
* 原理:`CyclicBarrier` 维护一个计数器 count。每次执行 `await` 方法之后,count 加 1,直到计数器的值和设置的值相等,等待的所有线程才会继续执行。
115+
116+
<p align="center">
117+
<img src="https://raw.githubusercontent.com/dunwu/javase-notes/master/images/concurrent/CyclicBarrier.png" alt="CyclicBarrier">
118+
</p>
119+
120+
### 源码
121+
122+
`CyclicBarrier` 提供了 2 个构造器
123+
124+
```java
125+
// parties 数相当于一个屏障,当 parties 数量的线程在等待时会跳闸,并且在跳闸时不执行预定义的动作。
126+
public CyclicBarrier(int parties) {}
127+
// parties 数相当于一个屏障,当 parties 数量的线程在等待时会跳闸,并且在跳闸时执行给定的动作 barrierAction。
128+
public CyclicBarrier(int parties, Runnable barrierAction) {}
129+
```
130+
131+
`CyclicBarrier` 的重要方法:
132+
133+
```java
134+
// 等待调用 await 的线程数达到屏障数。如果当前线程是最后一个到达的线程,并且在构造函数中提供了非空屏障操作,则当前线程在允许其他线程继续之前运行该操作。如果在屏障动作期间发生异常,那么该异常将在当前线程中传播并且屏障被置于断开状态。
135+
public int await() throws InterruptedException, BrokenBarrierException {}
136+
// 相比于上个方法,这个方法让这些线程等待至一定的时间,如果还有线程没有到达 barrier 状态就直接让到达 barrier 的线程执行后续任务。
137+
public int await(long timeout, TimeUnit unit)
138+
throws InterruptedException,
139+
BrokenBarrierException,
140+
TimeoutException {}
141+
// 将屏障重置为初始状态
142+
public void reset() {}
143+
```
144+
145+
### 示例
146+
147+
```java
148+
public class CyclicBarrierDemo02 {
149+
150+
static class CyclicBarrierRunnable implements Runnable {
151+
152+
CyclicBarrier barrier1 = null;
153+
CyclicBarrier barrier2 = null;
154+
155+
CyclicBarrierRunnable(CyclicBarrier barrier1, CyclicBarrier barrier2) {
156+
this.barrier1 = barrier1;
157+
this.barrier2 = barrier2;
158+
}
159+
160+
public void run() {
161+
try {
162+
Thread.sleep(1000);
163+
System.out.println(Thread.currentThread().getName() + " waiting at barrier 1");
164+
this.barrier1.await();
165+
166+
Thread.sleep(1000);
167+
System.out.println(Thread.currentThread().getName() + " waiting at barrier 2");
168+
this.barrier2.await();
169+
170+
System.out.println(Thread.currentThread().getName() + " done!");
171+
172+
} catch (InterruptedException | BrokenBarrierException e) {
173+
e.printStackTrace();
174+
}
175+
}
176+
}
177+
178+
public static void main(String[] args) {
179+
Runnable barrier1Action = () -> System.out.println("BarrierAction 1 executed ");
180+
Runnable barrier2Action = () -> System.out.println("BarrierAction 2 executed ");
181+
182+
CyclicBarrier barrier1 = new CyclicBarrier(2, barrier1Action);
183+
CyclicBarrier barrier2 = new CyclicBarrier(2, barrier2Action);
184+
185+
CyclicBarrierRunnable barrierRunnable1 = new CyclicBarrierRunnable(barrier1, barrier2);
186+
187+
CyclicBarrierRunnable barrierRunnable2 = new CyclicBarrierRunnable(barrier1, barrier2);
188+
189+
new Thread(barrierRunnable1).start();
190+
new Thread(barrierRunnable2).start();
191+
}
192+
}
193+
```
194+
195+
## Semaphore
196+
197+
### 要点
198+
199+
* 作用:字面意思为信号量。`Semaphore` 可以控制同时访问的线程个数。
200+
* 原理:`Semaphore` 初始化固定数量的 permit。每次执行 `acquire` 方法可以获取一个 permit,如果没有就等待;而 `release` 方法可以释放一个 permit。
201+
202+
<p align="center">
203+
<img src="https://raw.githubusercontent.com/dunwu/javase-notes/master/images/concurrent/semaphore.png" alt="semaphore">
204+
</p>
205+
206+
### 源码
207+
208+
`Semaphore`提供了 2 个构造器:
209+
210+
```java
211+
// 初始化固定数量的 permit,并且默认为非公平模式
212+
public Semaphore(int permits) {}
213+
// 初始化固定数量的 permit,第二个参数设置是否为公平模式。所谓公平,是指等待久的优先获取许可
214+
public Semaphore(int permits, boolean fair) {}
215+
```
216+
217+
`Semaphore`的重要方法:
218+
219+
```java
220+
// 获取 1 个许可
221+
public void acquire() throws InterruptedException {}
222+
//获取 permits 个许可
223+
public void acquire(int permits) throws InterruptedException {}
224+
// 释放 1 个许可
225+
public void release() {}
226+
//释放 permits 个许可
227+
public void release(int permits) {}
228+
```
229+
230+
### 示例
231+
232+
```java
233+
public class SemaphoreDemo {
234+
235+
private static final int THREAD_COUNT = 30;
236+
237+
private static ExecutorService threadPool = Executors.newFixedThreadPool(THREAD_COUNT);
238+
239+
private static Semaphore s = new Semaphore(10);
240+
241+
public static void main(String[] args) {
242+
for (int i = 0; i < THREAD_COUNT; i++) {
243+
threadPool.execute(() -> {
244+
try {
245+
s.acquire();
246+
System.out.println("save data");
247+
s.release();
248+
} catch (InterruptedException e) {
249+
e.printStackTrace();
250+
}
251+
});
252+
}
253+
254+
threadPool.shutdown();
255+
}
256+
}
257+
```
258+
259+
## 资料
260+
261+
* [Java 并发编程实战](https://item.jd.com/10922250.html)
262+
* [Java 并发编程的艺术](https://item.jd.com/11740734.html)
263+
* [Java 并发编程:CountDownLatch、CyclicBarrier 和 Semaphore](http://www.cnblogs.com/dolphin0520/p/3920397.html)

docs/concurrent/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@
44

55
[并发术语](并发术语.md)
66
[Java并发面试](Java并发面试.md)
7+
[Java并发工具类](Java并发工具类.md)

0 commit comments

Comments
 (0)