Java中的并发工具之一是Semaphore(信号量),它可以用于实现线程之间的同步和互斥。下面将详细介绍Semaphore的概念、用法和示例,以帮助您理解如何使用Semaphore来实现线程同步。
Semaphore是一种计数信号量,它主要用于控制对共享资源的访问。它维护了一个计数器,该计数器表示可用的通路数量。当线程需要访问共享资源时,首先尝试获取一个信号量,如果信号量计数大于零,则允许访问该资源,并将信号量计数减一;否则,线程将被阻塞,直到有一个通路可用。当线程完成对共享资源的访问后,释放信号量,将信号量计数加一,以允许其他线程访问共享资源。
Semaphore常用的方法有两个:
Semaphore可以用于以下情况:
下面是一个使用Semaphore实现线程同步的示例,假设有5个线程需要同时访问某个共享资源,但最多只能允许2个线程访问:
import java.util.concurrent.Semaphore;
public class SemaphoreExample {
private static final int THREAD_COUNT = 5;
private static final int MAX_PERMITS = 2;
private static Semaphore semaphore = new Semaphore(MAX_PERMITS);
public static void main(String[] args) {
for (int i = 0; i < THREAD_COUNT; i++) {
Thread thread = new Thread(new Worker(i));
thread.start();
}
}
static class Worker implements Runnable {
private int workerId;
public Worker(int workerId) {
this.workerId = workerId;
}
@Override
public void run() {
try {
System.out.println("Worker " + workerId + " is waiting...");
semaphore.acquire();
System.out.println("Worker " + workerId + " is accessing the shared resource.");
Thread.sleep(2000); // 模拟访问共享资源的耗时操作
System.out.println("Worker " + workerId + " has finished accessing the shared resource.");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
semaphore.release();
}
}
}
}
在上述示例中,我们创建了5个Worker线程,每个线程都会尝试获取一个信号量通路(acquire方法),如果信号量计数为0,则线程将被阻塞。当线程成功获取到通路后,它会打印访问共享资源的消息,并模拟对共享资源的访问操作。访问完成后,线程会释放信号量通路(release方法),以便其他线程可以继续访问共享资源。
通过运行上述示例,您可以观察到只有两个线程同时访问共享资源,其他线程需要等待释放通路后才能访问。
使用Semaphore可以灵活控制线程之间的同步和互斥,使多个线程能够安全地访问共享资源,避免竞态条件和数据不一致的问题。但要注意,信号量的计数应根据实际需求进行适当的设置,以避免死锁或资源浪费的情况发生。