Semaphore 在 Java 中的应用
1. 引言
在并发编程中,线程之间的协调和同步是非常重要的。Java 提供了多种机制来实现线程的同步,其中之一就是 Semaphore(信号量)。
Semaphore 是一个计数信号量,用于控制对共享资源的访问。它可以用来限制同时访问某个资源的线程数量,或者用来实现线程间的通信。
2. Semaphore 的概念
Semaphore 是一个整数计数器,用来控制同时访问某个资源的线程数量。
Semaphore 可以理解为停车场的例子,假设停车场有 3 个停车位,一共有 5 辆车要停进去。那么同时只能有 3 辆车进入停车场,其他的车就必须等待。
Semaphore 维护了一个计数器和一个等待队列。当线程请求资源时,如果计数器大于 0,表示有可用资源,计数器减 1,线程可以继续执行;如果计数器为 0,表示没有可用资源,线程就必须等待,进入等待队列。
3. Semaphore 的使用
在 Java 中,Semaphore 是通过 java.util.concurrent 包下的 Semaphore 类来实现的。
首先,我们需要创建一个 Semaphore 对象,并指定初始的许可数量。比如,我们可以创建一个初始许可数为 3 的 Semaphore:
Semaphore semaphore = new Semaphore(3);
然后,我们可以通过调用 acquire() 方法获取一个许可:
semaphore.acquire();
或者通过调用 release() 方法释放一个许可:
semaphore.release();
在调用 acquire() 方法时,如果许可数量不足,线程将会进入等待状态,直到有可用的许可为止。而调用 release() 方法会增加一个可用的许可。
4. Semaphore 的示例
下面我们通过一个示例来演示 Semaphore 的使用。
假设我们有一个任务队列,多个线程可以从队列中获取任务进行处理。但是,每次只能有固定数量的线程同时处理任务,其他的线程需要等待。
import java.util.concurrent.Semaphore;
class TaskQueue {
private Semaphore semaphore;
public TaskQueue(int permits) {
semaphore = new Semaphore(permits);
}
public void processTask() {
try {
semaphore.acquire();
// 模拟任务处理时间
Thread.sleep(1000);
System.out.println("Task processed by thread " + Thread.currentThread().getId());
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
semaphore.release();
}
}
}
class WorkerThread extends Thread {
private TaskQueue taskQueue;
public WorkerThread(TaskQueue taskQueue) {
this.taskQueue = taskQueue;
}
@Override
public void run() {
while (true) {
taskQueue.processTask();
}
}
}
public class SemaphoreExample {
public static void main(String[] args) {
TaskQueue taskQueue = new TaskQueue(3);
for (int i = 0; i < 5; i++) {
new WorkerThread(taskQueue).start();
}
}
}
在上面的示例中,我们创建了一个 TaskQueue 类来表示任务队列,它包含一个 Semaphore 对象。
在 processTask() 方法中,我们首先通过 acquire() 方法获取一个许可,如果没有可用的许可,线程将会进入等待状态。然后,我们模拟任务的处理时间,然后输出处理任务的线程 ID。最后,我们通过 release() 方法释放一个许可。
在 main() 方法中,我们创建了一个 TaskQueue 对象,并指定初始许可数为 3。然后,我们创建了 5 个 WorkerThread 线程,并启动它们。
运行上述代码,我们可以看到输出结果类似于下面的内容:
Task processed by thread 11
Task processed by thread 12
Task processed by thread 13
Task processed by thread 10
Task processed by thread 12
Task processed by thread 11
...
从输出结果中可以看出,每次只有 3 个线程同时处理任务,其他的线程需要等待。
5. 总结
通过本文,我们了解了 Semaphore 的概念和使用