-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSemaphoreDemo.java
More file actions
140 lines (128 loc) · 5.22 KB
/
Copy pathSemaphoreDemo.java
File metadata and controls
140 lines (128 loc) · 5.22 KB
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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package Phase7_Concurrency.Multithreading;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Semaphore
* ---------
* A counter that hands out PERMITS. acquire() blocks until a permit is
* available; release() returns one. With N permits you can let UP TO N
* threads through a section at once — classic resource-limiting tool.
* <p>
*
* Semaphore s = new Semaphore(N); // N permits
* s.acquire();
* try { ...use the resource... }
* finally { s.release(); }
* <p>
*
* What semaphores model
* ---------------------
* - A POOL of N identical resources (DB connections, HTTP threads,
* printers, GPU slots).
* - A CAP on concurrency — at most N requests in flight.
* - A signalling mechanism — release() can be called more times than
* acquire() (creating MORE permits than you started with).
* <p>
*
* Methods
* -------
* acquire() - take one permit, blocking
* acquireUninterruptibly() - ignore interrupts while waiting
* tryAcquire() - non-blocking attempt
* tryAcquire(time, unit) - timed attempt
* release() - return one permit
* acquire(n) / release(n) - permits in bulk
* availablePermits() - approx free count
* drainPermits() - take all available, return how many
* <p>
*
* Fair vs unfair
* --------------
* new Semaphore(N) - unfair, faster; possible starvation
* new Semaphore(N, true) - FIFO order; slower
* <p>
*
* "Binary semaphore" trick
* ------------------------
* new Semaphore(1) acts like a lock, but UNLIKE a ReentrantLock the
* thread that releases need NOT be the one that acquired. Useful for
* handing off control between threads (e.g., one thread acquires,
* another releases).
* <p>
*
* Pitfalls
* --------
* - Forgetting release() — try/finally always.
* - Releasing MORE than you acquired — silent permit inflation.
*/
public class SemaphoreDemo {
public static void main(String[] args) throws Exception {
section("1) Resource pool — at most 3 in flight at once");
Semaphore slots = new Semaphore(3);
AtomicInteger inFlight = new AtomicInteger();
Thread[] req = new Thread[8];
for (int i = 0; i < req.length; i++) {
final int id = i;
req[i] = new Thread(() -> {
try {
slots.acquire();
int n = inFlight.incrementAndGet();
System.out.println(" req " + id + " started (inFlight=" + n + ")");
Thread.sleep(80);
inFlight.decrementAndGet();
} catch (InterruptedException ie) { Thread.currentThread().interrupt(); }
finally { slots.release(); }
}, "req-" + id);
}
for (Thread t : req) t.start();
for (Thread t : req) t.join();
section("2) tryAcquire — bail out if no permit immediately");
Semaphore tight = new Semaphore(1);
tight.acquire(); // occupy the only permit
boolean got = tight.tryAcquire();
System.out.println("tryAcquire while empty = " + got);
boolean gotTimed = tight.tryAcquire(50, TimeUnit.MILLISECONDS);
System.out.println("tryAcquire(50ms) = " + gotTimed);
tight.release();
section("3) Binary semaphore — release from a different thread (handoff)");
Semaphore handoff = new Semaphore(0); // start empty
Thread consumer = new Thread(() -> {
try {
handoff.acquire();
System.out.println(" consumer woke up");
} catch (InterruptedException ignored) {}
}, "cons");
consumer.start();
Thread.sleep(50);
System.out.println("producer signalling");
handoff.release(); // signal
consumer.join();
section("4) Bulk permits — turnstile letting 2 threads through at a time");
Semaphore turnstile = new Semaphore(2);
for (int round = 1; round <= 3; round++) {
Thread a = new Thread(() -> doThroughTurnstile(turnstile), "a");
Thread b = new Thread(() -> doThroughTurnstile(turnstile), "b");
Thread c = new Thread(() -> doThroughTurnstile(turnstile), "c");
a.start(); b.start(); c.start();
a.join(); b.join(); c.join();
System.out.println("end of round " + round + ", permits=" + turnstile.availablePermits());
}
section("5) Fair semaphore");
Semaphore fair = new Semaphore(1, true);
System.out.println("isFair() = " + fair.isFair() + " (FIFO order)");
section("done");
}
private static void doThroughTurnstile(Semaphore s) {
try {
s.acquire();
System.out.println(" " + Thread.currentThread().getName() + " through");
Thread.sleep(30);
} catch (InterruptedException ignored) { Thread.currentThread().interrupt(); }
finally { s.release(); }
}
private static void section(String title) {
System.out.println();
System.out.println("=== " + title + " ===");
}
}