semaphore介绍
先说它的构造方法:
//参数permits是许可的数量
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
//fair为true的时候,semaphore保证在竞争permits的时候先进先出,先获得许可先执行
* 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);
}
公平信号量是指获得锁的顺序与线程启动的顺序有关,非公平信息量就是无关的了。
非公平信号量线程启动的顺序与调用semaphore.acquire()的顺序无关,也就是线程先启动了并不代表先获得许可。
公平与不公平通过Semaphore类的构造函数new Semaphore(int permits,boolean fair)的第二个参数fair决定。
再说说它的两个方法:
/**
//官方文档解释的很清楚,从semaphore(信号量)对象中获取一个许可,此semaphore许可permits数量会减1,如果当前许可的数量为0,
//线程会阻塞直到有可用的许可permit 或者线程被中断
* Acquires a permit from this semaphore, blocking until one is
* available, or the thread is {@linkplain Thread#interrupt interrupted}.
*
* <p>Acquires a permit, if one is available and returns immediately,
* reducing the number of available permits by one.
*
* <p>If no permit is available then the current thread becomes
* disabled for thread scheduling purposes and lies dormant until
* one of two things happens:
* <ul>
//此semaphore对象permits数量增加,需要其他线程调用此semaphore对象的release方法
* <li>Some other thread invokes the {@link #release} method for this
* semaphore and the current thread is next to be assigned a permit; or
* <li>Some other thread {@linkplain Thread#interrupt interrupts}
* the current thread.
* </ul>
*
* <p>If the current thread:
* <ul>
* <li>has its interrupted status set on entry to this method; or
* <li>is {@linkplain Thread#interrupt interrupted} while waiting
* for a permit,
* </ul>
* then {@link InterruptedException} is thrown and the current thread's
* interrupted status is cleared.
*
* @throws InterruptedException if the current thread is interrupted
*/
public void acquire() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
/**
* Releases a permit, returning it to the semaphore.
*
//释放一个许可,是permits的数量加1,
* <p>Releases a permit, increasing the number of available permits by
* one. If any threads are trying to acquire a permit, then one is
* selected and given the permit that was just released. That thread
* is (re)enabled for thread scheduling purposes.
*
* <p>There is no requirement that a thread that releases a permit must
* have acquired that permit by calling {@link #acquire}.
* Correct usage of a semaphore is established by programming convention
* in the application.
*/
public void release() {
sync.releaseShared(1);
}
顺序打印ABC思路
定义三个线程“ThreadA”、“ThreadB”、“ThreadC”它们的run()方法分别打印"A",“B”,“C”,我们定义三个信号量对象来控制线程ABC的执行顺序,初始化A信号量semaphore的permits的数量为1,线程ThreadA 执行run前调用信号量A对象的acquire()方法,所以A线程可以执行。初始化B、C信号量的permits数量为0,在线程ThreadB、ThreadC执行前分别调用B、C信号量的acquire()方法,由于permits的数量为0,所有ThreadB、ThreadC线程会阻塞。打印完“A”字母之后,我们调用B信号量的release()方法,这样阻塞的ThreadB线程就能顺利执行了,以此类推完成“A”,“B”,“C”的顺序打印。
import java.util.concurrent.Semaphore;
public class ABC_Semaphore {
// 以A开始的信号量,初始信号量数量为1
private static Semaphore A = new Semaphore(1,true);
// B、C信号量,A完成后开始,初始信号数量为0
private static Semaphore B = new Semaphore(0);
private static Semaphore C = new Semaphore(0);
static class ThreadA extends Thread {
@Override
public void run() {
try {
for (int i = 0; i < 10; i++) {
A.acquire();// A获取信号执行
System.out.println("A");
B.release();// B释放信号,B信号量为1,可以执行
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
static class ThreadB extends Thread {
@Override
public void run() {
try {
for (int i = 0; i < 10; i++) {
B.acquire();
System.out.println("B");
C.release();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
static class ThreadC extends Thread {
@Override
public void run() {
try {
for (int i = 0; i < 10; i++) {
C.acquire();
System.out.println("C");
System.out.println("---------------------");
A.release();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws InterruptedException {
//顺序打印abc
new ThreadA().start();
new ThreadB().start();
new ThreadC().start();
}