Semaphore是java.util.concurrent中的一个类,翻译成中文是“信号量”,它是一个计数器,使用场景基本上多线程访问共享资源,保护共享资源在某个时间只能被一个线程使用。
Semaphore原理
Semaphore相当于计数器,它可以增加,也可以减少,在初始化对象的时候,可以指定permits(信号量)数目,比如5,那么,Semaphore最多减少到0,最多增加不超过5。
显然,Semaphore更多时候被当作计数器来使用,当计数器为0的时候,线程处于等待状态,因此,它可以当作锁来使用。
在多线程编程中,使用Semaphore保护共享资源,一定要在线程中使用semaphore的acquire方法获取“信号量”,如果信号量大于0就可以使用共享资源,等于0则使用线程处于等待状态,直到其他线程使用完资源后调用release释放“信号量”
Semaphore使用
场景:使用Semaphore保证打印任务只能被多线程中的一个使用
PrintingJob.java
/**
* 提交任务给打印队列
* @Auothor wzx
* @Date 2017/3/11 0011
*/
public class PrintingJob implements Runnable {
private PrinterQueue printerQueue;
public PrintingJob(PrinterQueue printerQueue) {
this.printerQueue = printerQueue;
}
@Override
public void run() {
System.out.printf("%s: Going to print a document\n", Thread.currentThread().getName());
printerQueue.printJob(new Object());
}
}
PrinterQueue.java
/**
* 打印任务,使用semaphore保证
* @Auothor wzx
* @Date 2017/3/11 0011
*/
public class PrinterQueue {
private final Semaphore semaphore;
public PrinterQueue() {
this.semaphore = new Semaphore(1);
}
public void printJob(Object document) {
try {
semaphore.acquire();
long duration = (long) (Math.random() * 10000);
System.out.println(Thread.currentThread().getName() + ": PrintQueue: Printing a Job during " +
(duration/1000) + " seconds :: Time - " + new Date());
Thread.sleep(duration);
} catch(InterruptedException e) {
e.printStackTrace();
} finally {
System.out.printf("%s The document has been printed\n", Thread.currentThread().getName());
semaphore.release();
}
}
}
SemaphoreExample .java
/**
* 测试Semaphore
* @Auothor wzx
* @Date 2017/3/11 0011
*/
public class SemaphoreExample {
public static void main(String[] args) {
PrinterQueue printerQueue = new PrinterQueue();
Thread[] threads = new Thread[10];
for (int i = 0; i < 10; i++) {
threads[i] = new Thread(new PrintingJob(printerQueue));
}
for (int i = 0; i < 10; i++) {
threads[i].start();
}
}
}
输出如下:
Thread-0: Going to print a document
Thread-9: Going to print a document
Thread-8: Going to print a document
Thread-7: Going to print a document
Thread-6: Going to print a document
Thread-5: Going to print a document
Thread-4: Going to print a document
Thread-3: Going to print a document
Thread-2: Going to print a document
Thread-1: Going to print a document
Thread-0: PrintQueue: Printing a Job during 3 seconds :: Time - Sat Mar 11 20:01:40 CST 2017
Thread-0 The document has been printed
Thread-9: PrintQueue: Printing a Job during 3 seconds :: Time - Sat Mar 11 20:01:44 CST 2017
Thread-9 The document has been printed
Thread-8: PrintQueue: Printing a Job during 9 seconds :: Time - Sat Mar 11 20:01:47 CST 2017
Thread-8 The document has been printed
Thread-7: PrintQueue: Printing a Job during 5 seconds :: Time - Sat Mar 11 20:01:56 CST 2017
Thread-7 The document has been printed
Thread-6: PrintQueue: Printing a Job during 9 seconds :: Time - Sat Mar 11 20:02:01 CST 2017
Thread-6 The document has been printed
Thread-5: PrintQueue: Printing a Job during 9 seconds :: Time - Sat Mar 11 20:02:11 CST 2017
Thread-5 The document has been printed
Thread-4: PrintQueue: Printing a Job during 4 seconds :: Time - Sat Mar 11 20:02:21 CST 2017
Thread-4 The document has been printed
Thread-3: PrintQueue: Printing a Job during 3 seconds :: Time - Sat Mar 11 20:02:25 CST 2017
Thread-3 The document has been printed
Thread-2: PrintQueue: Printing a Job during 5 seconds :: Time - Sat Mar 11 20:02:28 CST 2017
Thread-2 The document has been printed
Thread-1: PrintQueue: Printing a Job during 6 seconds :: Time - Sat Mar 11 20:02:34 CST 2017
Thread-1 The document has been printed
使用步骤:
1.使用acquire()方法获取“信号量”;
2.对共享资源进行操作;
3.使用release()方法释放资源,为保证资源能安全释放,推荐写在finally代码块中;
参考
http://howtodoinjava.com/core-java/multi-threading/binary-semaphore-tutorial-and-example/