概述
Semaphore(信号量)用来控制同时访问特定资源的线程数量,简单地说就是限流。
可以把它比作是控制流量的红绿灯,Semaphore的初始化大小就是可以通过的绿灯流量,达到设定值转红灯无法获得资源。当有一辆车驶出,就能有一辆车获得绿灯通过。车可以理解为线程。
使用acquire()方法获得通行,使用release()方法释放。方法tryAcquire()如果返回true的话也获得了通行,不过得自己释放。
示例
指定可通行数为3,使4个线程同时去,也只能有3个获得通行。
若释放一个线程,就可以有一个线程可获得通行。
package semaphore;
import java.util.concurrent.Semaphore;
/**
* 可用来限流,控制同时访问特定资源的线程数量
* 红绿灯,特定数量的线程看到的是绿灯,其他的看到红灯,线程结束后,特定数量线程看到绿灯
* 可用于限制数据库连接
* acquire获得许可,结束后需要release表示结束。tryAcquire尝试获取许可
*
* @author bamboo
*
*/
public class TestSemaphore {
private static Semaphore s = new Semaphore(3);
public static void main(String[] args) {
for(int i = 0;i < 4;i++) {
new Thread(new ThreadA(s)).start();
}
try {
Thread.sleep(2000);
s.release();
System.out.println();
} catch (InterruptedException e) {
e.printStackTrace();
}
for(int i = 0;i < 2;i++) {
new Thread(new ThreadA(s)).start();
}
System.out.println(s.availablePermits());
System.out.println(s.getQueueLength());
System.out.println(s.hasQueuedThreads());
}
}
如果成功获得通行就可以获得特定的资源,否则就去做其他的。
package semaphore;
import java.util.concurrent.Semaphore;
public class ThreadA implements Runnable{
Semaphore semaphore;
ThreadA(Semaphore semaphore){
this.semaphore = semaphore;
}
@Override
public void run() {
try {
if(semaphore.tryAcquire()) {
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + " gets the green light");
}else {
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + " gets the red light");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
输出:
Thread-0 gets the green light
Thread-3 gets the red light
Thread-1 gets the green light
Thread-2 gets the green light
1
0
false
Thread-4 gets the green light
Thread-5 gets the red light
源码
如图可以看出Semaphore中抽象的静态内部类Sync,Sync继承自AQS队列同步器,AQS采用模板方法,自然Sync实现了一些父类方法。
Sync有两个子类,NonfairSync(非公平)和FairSync(公平版本子类)
两个构造方法
默认构造方法是非公平的。
/**
* Creates a {@code Semaphore} with the given number of
* permits and nonfair fairness setting.
*
* @param permits the initial number of permits available.
* This value may be negative, in which case releases
* must occur before any acquires will be granted.
*/
public Semaphore(int permits) {
sync = new NonfairSync(permits);
}
此构造方法可以指定是否采用公平的方式。
/**
* Creates a {@code Semaphore} with the given number of
* permits and the given fairness setting.
*
* @param permits the initial number of permits available.
* This value may be negative, in which case releases
* must occur before any acquires will be granted.
* @param fair {@code true} if this semaphore will guarantee
* first-in first-out granting of permits under contention,
* else {@code false}
*/
public Semaphore(int permits, boolean fair) {
sync = fair ? new FairSync(permits) : new NonfairSync(permits);
}
acquire()方法
获取指定个数的许可证
public void acquire(int permits) throws InterruptedException {
if (permits < 0) throw new IllegalArgumentException();
sync.acquireSharedInterruptibly(permits);
}
获取一个许可证
public void acquire() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
试图获得一个许可证
public boolean tryAcquire() {
return sync.nonfairTryAcquireShared(1) >= 0;
}
试图获得一个许可证,直到指定时间之前
public boolean tryAcquire(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
}
释放一个许可证
public void release() {
sync.releaseShared(1);
}
释放指定个数的许可证
public void release(int permits) {
if (permits < 0) throw new IllegalArgumentException();
sync.releaseShared(permits);
}
是否有线程等待获取许可证
/**
* Queries whether any threads are waiting to acquire. Note that
* because cancellations may occur at any time, a {@code true}
* return does not guarantee that any other thread will ever
* acquire. This method is designed primarily for use in
* monitoring of the system state.
*
* @return {@code true} if there may be other threads waiting to
* acquire the lock
*/
public final boolean hasQueuedThreads() {
return sync.hasQueuedThreads();
}
返回正在等待获取许可证的线程数
/**
* Returns an estimate of the number of threads waiting to acquire.
* The value is only an estimate because the number of threads may
* change dynamically while this method traverses internal data
* structures. This method is designed for use in monitoring of the
* system state, not for synchronization control.
*
* @return the estimated number of threads waiting for this lock
*/
public final int getQueueLength() {
return sync.getQueueLength();
}
返回此信号量中当前可用的许可证
/**
* Returns the current number of permits available in this semaphore.
*
* <p>This method is typically used for debugging and testing purposes.
*
* @return the number of permits available in this semaphore
*/
public int availablePermits() {
return sync.getPermits();
}