Java併發程式設計中Semaphore的用法
阿新 • • 發佈:2019-01-05
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