Semaphore 信号量
信号量, 是用来控制线程访问共享资源的数量. 它维护了一个可用的许可数量,线程在访问资源之前必须先获取许可,当许可数量不足时,线程需要等待其他线程释放许可。线程访问完资源后,需要释放许可,以便其他线程可以获取。
Semaphore`的主要操作包括:
acquire()
: 调用线程获取一个许可,如果semaphore中没有可用的许可,则线程会阻塞,直到有可用的许可为止。release()
: 工作线程释放一个许可,semaphore中增加许可的数量,并且通知等待的线程有新的许可可用。
import java.util.concurrent.Semaphore;
public class Main {
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(3); // 允许同时访问的线程数量为3
for (int i = 0; i < 5; i++) {
Thread thread = new Thread(() -> {
try {
semaphore.acquire(); // 获取许可
System.out.println("Thread " + Thread.currentThread().getId() + " acquired the permit.");
// 访问共享资源
Thread.sleep(1000);
semaphore.release(); // 释放许可
System.out.println("Thread " + Thread.currentThread().getId() + " released the permit.");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
thread.start();
}
}
}
acquire实现原理
acquire方法底层还是通过AQS来控制工作线程数量的
源码:
public void acquire() throws InterruptedException {
// 这个sync就是基于AQS实现的同步器
sync.acquireSharedInterruptibly(1);
}
// AQS中的方法
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
// 调用Semaphore中的tryAcquireShared方法, 返回值表示剩余信号量
if (tryAcquireShared(arg) < 0)
doAcquireSharedInterruptibly(arg);
}
// AQS中的方法, 阻塞等待
private void doAcquireSharedInterruptibly(int arg)
throws InterruptedException {
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
if (p == head) {
int r = tryAcquireShared(arg);
if (r >= 0) {
setHeadAndPropagate(node, r);
p.next = null; // help GC
failed = false;
return;
}
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
semaphore自己实现的sync源码, acquire最终调用的是nonfairTryAcquireShared方法
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 1192457210091910933L;
Sync(int permits) {
setState(permits);
}
final int getPermits() {
return getState();
}
final int nonfairTryAcquireShared(int acquires) {
for (;;) {
// state是AQS中的状态,这里表示信号量, 构造semaphore对象的时候, 会调用setState方法 将permits传入. 即state就是信号量大小
int available = getState();
int remaining = available - acquires;
if (remaining < 0 ||
compareAndSetState(available, remaining))
return remaining;
}
}
protected final boolean tryReleaseShared(int releases) {
for (;;) {
int current = getState();
int next = current + releases;
if (next < current) // overflow
throw new Error("Maximum permit count exceeded");
if (compareAndSetState(current, next))
return true;
}
}
final void reducePermits(int reductions) {
for (;;) {
int current = getState();
int next = current - reductions;
if (next > current) // underflow
throw new Error("Permit count underflow");
if (compareAndSetState(current, next))
return;
}
}
final int drainPermits() {
for (;;) {
int current = getState();
if (current == 0 || compareAndSetState(current, 0))
return current;
}
}
}