Skip to content

Commit 47f9d47

Browse files
committed
Add couple of tasks which used Semaphores
1 parent a258781 commit 47f9d47

File tree

4 files changed

+271
-0
lines changed

4 files changed

+271
-0
lines changed
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package by.andd3dfx.multithreading;
2+
3+
import java.util.concurrent.Semaphore;
4+
5+
/**
6+
* <pre>
7+
* https://leetcode.com/problems/building-h2o/description/
8+
*
9+
* There are two kinds of threads: oxygen and hydrogen. Your goal is to group these threads to form water molecules.
10+
*
11+
* There is a barrier where each thread has to wait until a complete molecule can be formed. Hydrogen and oxygen
12+
* threads will be given releaseHydrogen and releaseOxygen methods respectively, which will allow them to pass the
13+
* barrier. These threads should pass the barrier in groups of three, and they must immediately bond with each other
14+
* to form a water molecule. You must guarantee that all the threads from one molecule bond before any other threads
15+
* from the next molecule do.
16+
*
17+
* In other words:
18+
* If an oxygen thread arrives at the barrier when no hydrogen threads are present, it must wait for
19+
* two hydrogen threads.
20+
* If a hydrogen thread arrives at the barrier when no other threads are present, it must wait for
21+
* an oxygen thread and another hydrogen thread.
22+
*
23+
* We do not have to worry about matching the threads up explicitly; the threads do not necessarily know which
24+
* other threads they are paired up with. The key is that threads pass the barriers in complete sets; thus, if we
25+
* examine the sequence of threads that bind and divide them into groups of three, each group should contain one
26+
* oxygen and two hydrogen threads.
27+
*
28+
* Write synchronization code for oxygen and hydrogen molecules that enforces these constraints.
29+
*
30+
* Example 1:
31+
* Input: water = "HOH"
32+
* Output: "HHO"
33+
* Explanation: "HOH" and "OHH" are also valid answers.
34+
*
35+
* Example 2:
36+
* Input: water = "OOHHHH"
37+
* Output: "HHOHHO"
38+
* Explanation: "HOHHHO", "OHHHHO", "HHOHOH", "HOHHOH", "OHHHOH", "HHOOHH", "HOHOHH" and "OHHOHH" are also valid
39+
* answers.
40+
*
41+
* Constraints:
42+
* 3 * n == water.length
43+
* 1 <= n <= 20
44+
* water[i] is either 'H' or 'O'.
45+
* There will be exactly 2 * n 'H' in water.
46+
* There will be exactly n 'O' in water.
47+
*
48+
* Initial code:
49+
* class H2O {
50+
* public void hydrogen(Runnable releaseHydrogen) throws InterruptedException {
51+
* // releaseHydrogen.run() outputs "H". Do not change or remove this line.
52+
* releaseHydrogen.run();
53+
* }
54+
*
55+
* public void oxygen(Runnable releaseOxygen) throws InterruptedException {
56+
* // releaseOxygen.run() outputs "O". Do not change or remove this line.
57+
* releaseOxygen.run();
58+
* }
59+
* }
60+
* </pre>
61+
*/
62+
public class BuildingH2O {
63+
64+
private Semaphore hydrogenSemaphore = new Semaphore(2);
65+
private Semaphore oxygenSemaphore = new Semaphore(1);
66+
67+
public void hydrogen(Runnable releaseHydrogen) throws InterruptedException {
68+
oxygenSemaphore.acquire();
69+
70+
// releaseHydrogen.run() outputs "H". Do not change or remove this line.
71+
releaseHydrogen.run();
72+
hydrogenSemaphore.release();
73+
}
74+
75+
public void oxygen(Runnable releaseOxygen) throws InterruptedException {
76+
hydrogenSemaphore.acquire(2);
77+
78+
// releaseOxygen.run() outputs "O". Do not change or remove this line.
79+
releaseOxygen.run();
80+
oxygenSemaphore.release(2);
81+
}
82+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package by.andd3dfx.multithreading;
2+
3+
import java.util.concurrent.Semaphore;
4+
5+
/**
6+
* <pre>
7+
* https://leetcode.com/problems/print-in-order/
8+
*
9+
* Suppose we have a class:
10+
*
11+
* public class Foo {
12+
* public void first() { print("first"); }
13+
* public void second() { print("second"); }
14+
* public void third() { print("third"); }
15+
* }
16+
*
17+
* The same instance of Foo will be passed to three different threads. Thread A will call first(), thread B will
18+
* call second(), and thread C will call third(). Design a mechanism and modify the program to ensure that second()
19+
* is executed after first(), and third() is executed after second().
20+
*
21+
* Note:
22+
* We do not know how the threads will be scheduled in the operating system, even though the numbers in the input seem
23+
* to imply the ordering. The input format you see is mainly to ensure our tests' comprehensiveness.
24+
*
25+
* Example 1:
26+
* Input: nums = [1,2,3]
27+
* Output: "firstsecondthird"
28+
* Explanation: There are three threads being fired asynchronously. The input [1,2,3] means thread A calls first(),
29+
* thread B calls second(), and thread C calls third(). "firstsecondthird" is the correct output.
30+
*
31+
* Example 2:
32+
* Input: nums = [1,3,2]
33+
* Output: "firstsecondthird"
34+
* Explanation: The input [1,3,2] means thread A calls first(), thread B calls third(), and thread C calls second().
35+
* "firstsecondthird" is the correct output.
36+
*
37+
* Constraints:
38+
* nums is a permutation of [1, 2, 3].
39+
*
40+
* Initial code:
41+
* class H2O {
42+
* public void first(Runnable printFirst) throws InterruptedException {
43+
* // printFirst.run() outputs "first". Do not change or remove this line.
44+
* printFirst.run();
45+
* }
46+
* public void second(Runnable printSecond) throws InterruptedException {
47+
* // printSecond.run() outputs "second". Do not change or remove this line.
48+
* printSecond.run();
49+
* }
50+
* public void third(Runnable printThird) throws InterruptedException {
51+
* // printThird.run() outputs "third". Do not change or remove this line.
52+
* printThird.run();
53+
* }
54+
* }
55+
* </pre>
56+
*/
57+
public class PrintInOrder {
58+
59+
private Semaphore semaphore2 = new Semaphore(0);
60+
private Semaphore semaphore3 = new Semaphore(0);
61+
62+
public void first(Runnable printFirst) throws InterruptedException {
63+
// printFirst.run() outputs "first". Do not change or remove this line.
64+
printFirst.run();
65+
semaphore2.release();
66+
}
67+
68+
public void second(Runnable printSecond) throws InterruptedException {
69+
semaphore2.acquire();
70+
// printSecond.run() outputs "second". Do not change or remove this line.
71+
printSecond.run();
72+
semaphore3.release();
73+
}
74+
75+
public void third(Runnable printThird) throws InterruptedException {
76+
semaphore3.acquire();
77+
// printThird.run() outputs "third". Do not change or remove this line.
78+
printThird.run();
79+
}
80+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package by.andd3dfx.multithreading;
2+
3+
import lombok.SneakyThrows;
4+
import org.junit.Test;
5+
6+
import static org.assertj.core.api.Assertions.assertThat;
7+
import static org.junit.Assert.assertFalse;
8+
import static org.junit.Assert.assertTrue;
9+
10+
public class BuildingH2OTest {
11+
12+
private final int MOLECULES_COUNT = 3;
13+
14+
@Test
15+
public void checkPrintingOrder() throws InterruptedException {
16+
var buildingH2O = new BuildingH2O();
17+
18+
var result = run(buildingH2O);
19+
20+
assertFalse("String result should not be empty", result.isBlank());
21+
assertThat(result.length() % 3).isEqualTo(0);
22+
23+
for (int i = 0; i < result.length() / 3; i++) {
24+
var molecule = result.substring(3 * i, 3 * i + 3);
25+
System.out.println(molecule);
26+
assertTrue(molecule.equals("OHH") || molecule.equals("HOH") || molecule.equals("HHO"));
27+
}
28+
}
29+
30+
private String run(BuildingH2O buildingH2O) throws InterruptedException {
31+
var sb = new StringBuilder();
32+
33+
for (int i = 0; i < MOLECULES_COUNT; i++) {
34+
new Thread(
35+
() -> oxygen(buildingH2O, () -> sb.append("O"))
36+
).start();
37+
}
38+
for (int i = 0; i < 2 * MOLECULES_COUNT; i++) {
39+
new Thread(
40+
() -> hydrogen(buildingH2O, () -> sb.append("H"))
41+
).start();
42+
}
43+
44+
Thread.sleep(100);
45+
46+
return sb.toString();
47+
}
48+
49+
@SneakyThrows
50+
private void hydrogen(BuildingH2O buildingH2O, Runnable runnable) {
51+
buildingH2O.hydrogen(runnable);
52+
}
53+
54+
@SneakyThrows
55+
private void oxygen(BuildingH2O buildingH2O, Runnable runnable) {
56+
buildingH2O.oxygen(runnable);
57+
}
58+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package by.andd3dfx.multithreading;
2+
3+
import lombok.SneakyThrows;
4+
import org.junit.Test;
5+
6+
import static org.assertj.core.api.Assertions.assertThat;
7+
8+
public class PrintInOrderTest {
9+
10+
@Test
11+
public void checkPrintingOrder() throws InterruptedException {
12+
var printInOrder = new PrintInOrder();
13+
14+
// Check task requirements
15+
var result = run(printInOrder);
16+
assertThat(result).isEqualTo("firstsecondthird");
17+
18+
// Check could class pass required procedure second time
19+
var result2 = run(printInOrder);
20+
assertThat(result2).isEqualTo("firstsecondthird");
21+
}
22+
23+
private String run(PrintInOrder printInOrder) throws InterruptedException {
24+
var sb = new StringBuilder();
25+
var thread1 = new Thread(() -> printFirst(printInOrder, () -> sb.append("first")));
26+
var thread2 = new Thread(() -> printSecond(printInOrder, () -> sb.append("second")));
27+
var thread3 = new Thread(() -> printThird(printInOrder, () -> sb.append("third")));
28+
thread3.start();
29+
thread2.start();
30+
thread1.start();
31+
32+
Thread.sleep(50);
33+
34+
return sb.toString();
35+
}
36+
37+
@SneakyThrows
38+
private void printFirst(PrintInOrder printInOrder, Runnable runnable) {
39+
printInOrder.first(runnable);
40+
}
41+
42+
@SneakyThrows
43+
private void printSecond(PrintInOrder printInOrder, Runnable runnable) {
44+
printInOrder.second(runnable);
45+
}
46+
47+
@SneakyThrows
48+
private void printThird(PrintInOrder printInOrder, Runnable runnable) {
49+
printInOrder.third(runnable);
50+
}
51+
}

0 commit comments

Comments
 (0)