|
2020-09-04
Semaphores(信号)是一个线程同步结构,它既可以用于线程通信以避免丢失信号,也可以像锁一样使关键代码(介于lock和unlock之间的代码)在多个线程之间同步运行。
Java 5 提供了 java.util.concurrent.Semaphore 类,所以你可以不需要自己实现 Semaphore,但我们需要知道它的原理并使用它。
1. 简单的 Semaphore
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| /** * @author : sungm * @date : 2020-09-04 15:38 */ public class Semaphore {
private boolean signal = false;
public synchronized void take() { this.signal = true; this.notify(); }
public synchronized void release() throws InterruptedException { while (this.signal) { this.wait(); } this.signal = false; }
}
|
take() 方法发送一个信号,release() 方法等待信号。
使用 Semaphore 可以避免丢失信号。 我们可以使用 take() 方法代替 notify(),使用 release() 方法代替 wait()。如果 take() 方法的调用发生在 release() 方法之前,信号标志 signal = true 被保存下来,等到release() 方法被调用时便不满足自旋条件,不进入wait() 方法,因此而避免了信号丢失的情况发生。
2. 使用 Semaphore
示例:
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
| /** * @author : sungm * @date : 2020-09-04 15:50 */ public class Main {
public static void main(String[] args) { Semaphore semaphore = new Semaphore();
//发送信号的线程 Thread sendingThread = new Thread(semaphore::take, "SendingThread");
//接收信号的线程 Thread receivingThread = new Thread(() -> { try { semaphore.release(); } catch (Exception e) {
} }, "ReceivingThread");
sendingThread.start(); receivingThread.start(); } }
|
3. Semaphore 计数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| /** * @author : sungm * @date : 2020-09-04 15:38 */ public class Semaphore {
private int signal = 0;
public synchronized void take() { this.signal++; this.notify(); }
public synchronized void release() throws InterruptedException { while (this.signal != 0) { this.wait(); } this.signal--; }
}
|
4. 有限 Semaphore
Semaphore 计数没有设置信号上限,我们可以给Semaphore设置上线。如下所示:
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
| /** * @author : sungm * @date : 2020-09-04 16:00 */ public class BoundedSemaphore {
private int signal = 0; private int bound = 0;
/** * 构造函数注入 Semaphore 上限 * * @param bound 界限(signal的最大值) */ public BoundedSemaphore(int bound) { this.bound = bound; }
public synchronized void take() throws InterruptedException { while (this.signal == this.bound) { this.wait(); } this.signal++; this.notify(); }
public synchronized void release() throws InterruptedException { while (this.signal == 0) { this.wait(); } this.signal--; this.notify(); }
}
|
当发送的信号已经达到上限,那么发送信号的线程会进入等待,直到接收信号的线程消耗了一个信号,等待中的发送信号线程才可能被唤醒。
5. Semaphore 当成Lock使用
1 2 3 4 5 6
| semaphore.take(); try { //同步代码 } finally { semaphore.release(); }
|