Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 2feac95

Browse files
committed
feat: add leetcode question #1117
1 parent 9b0937c commit 2feac95

File tree

8 files changed

+257
-5
lines changed

8 files changed

+257
-5
lines changed
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package com.hi.dhl.algorithms.other.concurrency._1117;
2+
3+
import java.util.concurrent.CyclicBarrier;
4+
import java.util.concurrent.Semaphore;
5+
6+
/**
7+
* <pre>
8+
* author: dhl
9+
* date : 2020年11月1日
10+
* desc :
11+
* </pre>
12+
*/
13+
class H2O {
14+
15+
private Semaphore sh = new Semaphore(2);
16+
private Semaphore so = new Semaphore(1);
17+
private CyclicBarrier cb = new CyclicBarrier(3, new Runnable() {
18+
@Override
19+
public void run() {
20+
// 两个氢线程 和 一个氧线程 都到达之后,释放 H 和 0的信号量
21+
sh.release(2);
22+
so.release(1);
23+
}
24+
});
25+
26+
public H2O() {
27+
28+
}
29+
30+
public void hydrogen(Runnable releaseHydrogen) throws InterruptedException {
31+
32+
// releaseHydrogen.run() outputs "H". Do not change or remove this line.
33+
sh.acquire();
34+
releaseHydrogen.run();
35+
try {
36+
cb.await();
37+
} catch (Exception e) {
38+
39+
}
40+
}
41+
42+
public void oxygen(Runnable releaseOxygen) throws InterruptedException {
43+
44+
// releaseOxygen.run() outputs "O". Do not change or remove this line.
45+
so.acquire();
46+
releaseOxygen.run();
47+
try {
48+
cb.await();
49+
} catch (Exception e) {
50+
51+
}
52+
}
53+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package com.hi.dhl.algorithms.other.concurrency._1117;
2+
3+
import java.util.concurrent.CyclicBarrier;
4+
import java.util.concurrent.Semaphore;
5+
6+
/**
7+
* <pre>
8+
* author: dhl
9+
* date : 2020年11月1日
10+
* desc :
11+
* </pre>
12+
*/
13+
class H2O1 {
14+
private Semaphore sh = new Semaphore(2);
15+
private Semaphore so = new Semaphore(0);
16+
17+
public H2O1() {
18+
19+
}
20+
21+
public void hydrogen(Runnable releaseHydrogen) throws InterruptedException {
22+
sh.acquire();
23+
// releaseHydrogen.run() outputs "H". Do not change or remove this line.
24+
releaseHydrogen.run();
25+
so.release();
26+
}
27+
28+
public void oxygen(Runnable releaseOxygen) throws InterruptedException {
29+
so.acquire(2); // 等待 两个氢线程 到了之后,才能执行 氧线程
30+
// releaseOxygen.run() outputs "O". Do not change or remove this line.
31+
releaseOxygen.run();
32+
sh.release(2);
33+
}
34+
}

‎README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
剑指 offer 及大厂面试题解:<a href ="https://offer.hi-dhl.com">在线阅读</a>,LeetCode 系列题解:<a href ="https://leetcode.hi-dhl.com">在线阅读</a>
77
</p>
88

9-
<p align="center"> 做题进度:AC 130 题,每道题目都会用 Java 和 kotlin 去实现</p>
9+
<p align="center"> 做题进度:AC 131 题,每道题目都会用 Java 和 kotlin 去实现</p>
1010

1111
<p align="center"> 每题都有解题思路、时间复杂度、空间复杂度、源代码</p>
1212

‎leetcode/_coverpage.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
<img src="http://cdn.51git.cn/2020-10-04-16017893774760.jpg" width = 400px/>
99

1010

11-
LeetCode 的题解进度,目前累计 AC 了 130 题,累计题解 57
11+
LeetCode 的题解进度,目前累计 AC 了 131 题,累计题解 58
1212

1313

1414
如果你同我一样喜欢算法、LeetCode,可以关注我 GitHub 上的 LeetCode 题解

‎leetcode/common/index_header.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
<p align="center"> 仓库 <b>每周</b> 持续更新,如果对你有帮助,请在右上角 star 一下</p>
44

5-
<!--<p align="center"> LeetCode 的题解进度,目前已经 AC 了 129 题,题解 30 题 </p>-->
5+
<p align="center"> LeetCode 的题解进度,目前已经 AC 了 131 题</p>
66

77
<p align="center"> 每题都有解题思路、时间复杂度、空间复杂度、源代码</p>
88

‎offer/_coverpage.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
<img src="http://cdn.51git.cn/2020-10-04-16017893774760.jpg" width = 400px/>
99

1010

11-
LeetCode 的题解进度,目前累计 AC 了 130 题,累计题解 57
11+
LeetCode 的题解进度,目前累计 AC 了 131 题,累计题解 58
1212

1313

1414
如果你同我一样喜欢算法、LeetCode,可以关注我 GitHub 上的 LeetCode 题解

‎offer/common/index_header.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
<p align="center"> 仓库 <b>每周</b> 持续更新,如果对你有帮助,请在右上角 star 一下</p>
44

5-
<!--<p align="center"> 剑指 Offer 共 72 题,目前已经 AC 了 52 题,题解进度 28 题 </p>-->
5+
<p align="center"> LeetCode 的题解进度,目前已经 AC 了 131 题</p>
66

77
<p align="center"> 每题都有解题思路、时间复杂度、空间复杂度、源代码 </p>
88

‎offer/multi-thread/06-h20.md‎

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
题目来源于 LeetCode 多线程 第 1117 号问题:H2O 生成。题目难度为 Middle。
2+
3+
* [中文地址:https://leetcode-cn.com/problems/building-h2o](https://leetcode-cn.com/problems/building-h2o)
4+
5+
## 题目描述
6+
7+
现在有两种线程,氧 `oxygen` 和氢 `hydrogen`,你的目标是组织这两种线程来产生水分子。
8+
9+
存在一个屏障(barrier)使得每个线程必须等候直到一个完整水分子能够被产生出来。
10+
11+
12+
氢和氧线程会被分别给予 `releaseHydrogen``releaseOxygen` 方法来允许它们突破屏障。
13+
14+
15+
这些线程应该三三成组突破屏障并能立即组合产生一个水分子。
16+
17+
你必须保证产生一个水分子所需线程的结合必须发生在下一个水分子产生之前。
18+
19+
换句话说:
20+
21+
* 如果一个氧线程到达屏障时没有氢线程到达,它必须等候直到两个氢线程到达。
22+
* 如果一个氢线程到达屏障时没有其它线程到达,它必须等候直到一个氧线程和另一个氢线程到达。
23+
24+
25+
26+
**示例 1:**
27+
28+
```
29+
输入: "HOH"
30+
输出: "HHO"
31+
解释: "HOH" 和 "OHH" 依然都是有效解。
32+
```
33+
34+
**示例 2:**
35+
36+
```
37+
输入: "OOHHHH"
38+
输出: "HHOHHO"
39+
解释: "HOHHHO", "OHHHHO", "HHOHOH", "HOHHOH", "OHHHOH", "HHOOHH", "HOHOHH" 和 "OHHOHH" 依然都是有效解。
40+
```
41+
42+
## 思路:
43+
44+
这道题主要考多线程当中的 Semaphore(信号量) 和 CyclicBarrier 的使用,主要介绍这两种实现方式:
45+
46+
* Semaphore + CyclicBarrier 实现
47+
* Semaphore 实现
48+
49+
根据题意分析:
50+
51+
* 如果一个氧线程到达屏障时没有氢线程到达,它必须等候直到两个氢线程到达。
52+
* 如果一个氢线程到达屏障时没有其它线程到达,它必须等候直到一个氧线程和另一个氢线程到达。
53+
54+
无论是 **氢线程** 还是 **氧线程** 先到达,都必须满足一个条件: **两个氢线程****一个氧线程** 都必须到达才能继续往下执行。满足 CyclicBarrier 的特点。
55+
56+
**CyclicBarrier** 的作用是让一组线程全部达到一个状态之后再全部同时执行,而且他有一个特点就是所有线程执行完毕之后是可以重用的。
57+
58+
那么如何控制 H 和 0 的输出顺序呢,可以使用 Semaphore(信号量),Semaphore 有以下几个方法:
59+
60+
**构造方法:**
61+
62+
```
63+
// 默认创建公平锁
64+
// permits 表示同一时间访问共享资源的线程数
65+
public Semaphore(int permits) {
66+
sync = new NonfairSync(permits);
67+
}
68+
69+
private Semaphore sh = new Semaphore(2);
70+
private Semaphore so = new Semaphore(1);
71+
```
72+
73+
其中 permits 的值直接传给了 AQS 父类,也就是设置了 AQS 的 state 属性,表示允许多少个线程来访问:
74+
75+
* `Semaphore(2)` 表示允许两个氢线程
76+
* `Semaphore(1)` 表示允许一个氧线程
77+
78+
**acquire() 方法**
79+
80+
当线程调用了 `acquire()` 方法, 对 state 值减 1。当 `state` 等于 0,再次调用 `acquire()` 方法,线程将会被加入到同步队列并阻塞,直到其他线程调用 `release()` 方法,对 state 值加 1 ,当前线程才可以继续访问。
81+
82+
`acquire(2)` 方法表示获得两个许可才能继续执行,否则处于阻塞状态,对 state 值减 2
83+
84+
**release() 方法**
85+
86+
调用 `release()` 方法,对 state 值加 1。每次调用 `acquire()` 方法的时候,一定要保证 `release()` 方法的执行, 否则会导致资源一直无法释放,另外需要注意的是 `acquire()` 方法 和 `release()` 一定是成对出现的。
87+
88+
`release(2)` 方法表示释放两个许可,对 state 值加 2
89+
90+
91+
> Java 和 Kotlin 实现大体上一致,这里主要演示 Java 的写法。
92+
93+
### Semaphore + CyclicBarrier 实现
94+
95+
```
96+
class H2O {
97+
98+
private Semaphore sh = new Semaphore(2);
99+
private Semaphore so = new Semaphore(1);
100+
private CyclicBarrier cb = new CyclicBarrier(3, new Runnable() {
101+
@Override
102+
public void run() {
103+
// 两个氢线程 和 一个氧线程 都到达之后,释放 H 和 0的信号量
104+
sh.release(2);
105+
so.release(1);
106+
}
107+
});
108+
109+
public H2O() {
110+
111+
}
112+
113+
public void hydrogen(Runnable releaseHydrogen) throws InterruptedException {
114+
115+
// releaseHydrogen.run() outputs "H". Do not change or remove this line.
116+
sh.acquire();
117+
releaseHydrogen.run();
118+
try {
119+
cb.await();
120+
} catch (Exception e) {
121+
122+
}
123+
}
124+
125+
public void oxygen(Runnable releaseOxygen) throws InterruptedException {
126+
127+
// releaseOxygen.run() outputs "O". Do not change or remove this line.
128+
so.acquire();
129+
releaseOxygen.run();
130+
try {
131+
cb.await();
132+
} catch (Exception e) {
133+
134+
}
135+
}
136+
}
137+
```
138+
139+
### Semaphore 实现
140+
141+
```
142+
class H2O {
143+
private Semaphore sh = new Semaphore(2);
144+
private Semaphore so = new Semaphore(0);
145+
146+
public H2O() {
147+
148+
}
149+
150+
public void hydrogen(Runnable releaseHydrogen) throws InterruptedException {
151+
sh.acquire();
152+
// releaseHydrogen.run() outputs "H". Do not change or remove this line.
153+
releaseHydrogen.run();
154+
so.release();
155+
}
156+
157+
public void oxygen(Runnable releaseOxygen) throws InterruptedException {
158+
so.acquire(2); // 等待 两个氢线程 到了之后,才能执行 氧线程
159+
// releaseOxygen.run() outputs "O". Do not change or remove this line.
160+
releaseOxygen.run();
161+
sh.release(2);
162+
}
163+
}
164+
```
165+

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /