java併發程式設計之Semaphore(訊號量)的用法
阿新 • • 發佈:2019-01-15
Semaphore類其實就是synchronized關鍵字的升級版,這個類主要作用就是控制執行緒併發的數量,而在這方面synchronized就有點力不足了,接下來我們就開始先了解一下Semaphore的一些常用方法就注意細節。
在new 這個類的時候需要給這個類傳遞一個引數permits,這個引數是整數型別,這個引數的意思是同一時間內,最多允許多少個執行緒同時執行acquire方法和release方法之間的程式碼,如果方法acquire沒有引數則預設是一個許可。下面我們用程式碼進行驗證。
Semaphore又稱訊號量,是作業系統中的一個概念,在Java併發程式設計中,訊號量控制的是執行緒併發的數量。
public Semaphore(int permits)
其中引數permits就是允許同時執行的執行緒數目;
下面先看一個訊號量實現單執行緒的例子,也就是permits=1:
package concurrent.semaphore; import java.util.concurrent.Semaphore; public class Driver { // 控制執行緒的數目為1,也就是單執行緒 private Semaphore semaphore = new Semaphore(1); public void driveCar() { try { // 從訊號量中獲取一個允許機會 semaphore.acquire(); System.out.println(Thread.currentThread().getName() + " start at " + System.currentTimeMillis()); Thread.sleep(1000); System.out.println(Thread.currentThread().getName() + " stop at " + System.currentTimeMillis()); // 釋放允許,將佔有的訊號量歸還 semaphore.release(); } catch (InterruptedException e) { e.printStackTrace(); } } }
package concurrent.semaphore;
public class Car extends Thread{
private Driver driver;
public Car(Driver driver) {
super();
this.driver = driver;
}
public void run() {
driver.driveCar();
}
}
public class Run { public static void main(String[] args) { Driver driver = new Driver(); for (int i = 0; i < 5; i++) { (new Car(driver)).start(); } } }
執行結果:
Thread-0 start at 1482664517179
Thread-0 stop at 1482664518179
Thread-3 start at 1482664518179
Thread-3 stop at 1482664519179
Thread-1 start at 1482664519179
Thread-1 stop at 1482664520179
Thread-4 start at 1482664520179
Thread-4 stop at 1482664521180
Thread-2 start at 1482664521180
Thread-2 stop at 1482664522180
從輸出可以看出,改輸出與單執行緒是一樣的,執行完一個執行緒,再執行另一個執行緒。
如果訊號量大於1呢,我們將訊號量設為3:
public class Driver {
// 將訊號量設為3
private Semaphore semaphore = new Semaphore(3);
public void driveCar() {
try {
semaphore.acquire();
System.out.println(Thread.currentThread().getName() + " start at " + System.currentTimeMillis());
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + " stop at " + System.currentTimeMillis());
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
輸出:
Thread-0 start at 1482665412515
Thread-3 start at 1482665412517
Thread-1 start at 1482665412517
Thread-3 stop at 1482665413517
Thread-0 stop at 1482665413517
Thread-4 start at 1482665413517
Thread-2 start at 1482665413517
Thread-1 stop at 1482665413518
Thread-4 stop at 1482665414517
Thread-2 stop at 1482665414517
從輸出的前三行可以看出,有3個執行緒可以同時執行,三個執行緒同時執行的時候,第四個執行緒必須等待前面有一個要完成,才能執行第四個執行緒啟動。
當然也可以用acquire動態地新增permits的數量,它表示的是一次性獲取許可的數量,比如:
public class Driver {
// 訊號量共10個
private Semaphore semaphore = new Semaphore(10);
public void driveCar() {
try {
// 每次獲取3個
semaphore.acquire(3);
System.out.println(Thread.currentThread().getName() + " start at " + System.currentTimeMillis());
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + " stop at " + System.currentTimeMillis());
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
在上述程式碼中總的訊號量除以每次獲取的許可數即10/3=3,就是說可以允許3個執行緒一起執行。
我們可以用public int availablePermits()
檢視現在可用的訊號量:
public class SemaphoreAvaliablePermits {
public static void main(String[] args) {
try{
Semaphore semaphore = new Semaphore(10);
System.out.println("Semaphore available permits: " + semaphore.availablePermits());
semaphore.acquire();
System.out.println("Semaphore available permits: " + semaphore.availablePermits());
semaphore.acquire(2);
System.out.println("Semaphore available permits: " + semaphore.availablePermits());
semaphore.acquire(3);
System.out.println("Semaphore available permits: " + semaphore.availablePermits());
semaphore.acquire(4);
System.out.println("Semaphore available permits: " + semaphore.availablePermits());
semaphore.release();
System.out.println("Semaphore available permits: " + semaphore.availablePermits());
semaphore.release(2);
System.out.println("Semaphore available permits: " + semaphore.availablePermits());
semaphore.release(3);
System.out.println("Semaphore available permits: " + semaphore.availablePermits());
semaphore.release(4);
System.out.println("Semaphore available permits: " + semaphore.availablePermits());
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
輸出:
Semaphore available permits: 10
Semaphore available permits: 9
Semaphore available permits: 7
Semaphore available permits: 4
Semaphore available permits: 0
Semaphore available permits: 1
Semaphore available permits: 3
Semaphore available permits: 6
Semaphore available permits: 10
還有一個方法public int drainPermits()
,這個方法返回即可所有的許可數目,並將許可置0:
public class SemaphoreDrainPermits {
public static void main(String[] args) {
try{
Semaphore semaphore = new Semaphore(10);
System.out.println("Semaphore available permits: " + semaphore.availablePermits());
semaphore.acquire();
System.out.println("Semaphore available permits: " + semaphore.availablePermits());
System.out.println("Semaphore drain permits" + semaphore.drainPermits());
System.out.println("Semaphore available permits: " + semaphore.availablePermits());
System.out.println("Semaphore drain permits" + semaphore.drainPermits());
System.out.println("Semaphore available permits: " + semaphore.availablePermits());
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
輸出:
Semaphore available permits: 10
Semaphore available permits: 9
Semaphore drain permits9
Semaphore available permits: 0
Semaphore drain permits0
Semaphore available permits: 0