1. 程式人生 > >java併發程式設計之Semaphore(訊號量)的用法

java併發程式設計之Semaphore(訊號量)的用法

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

相關推薦

no