java中的計數訊號量(Counting Semaphore)

來源:互聯網
上載者:User

標籤:semaphore   計數資訊量   java訊號量   

訊號量(Semaphore)又稱為訊號量、旗語,它以一個整數變數,提供訊號,以確保在並行計算環境中,不同進程在訪問共用資源時,不會發生衝突。是一種不需要使用忙碌等待(busy waiting)的一種方法。

訊號量的概念是由荷蘭電腦科學家艾茲格·迪傑斯特拉(Edsger W. Dijkstra)發明的,廣泛的應用於不同的作業系統中。在系統中,給予每一個進程一個訊號量,代表每個進程目前的狀態,未得到控制權的進程會在特定地方被強迫停下來,等待可以繼續進行的訊號到來。如果訊號量是一個任意的整數,通常被稱為計數訊號量(Counting semaphore),或一般訊號量(general semaphore);如果訊號量只有二進位的0或1,稱為二進位訊號量(binary semaphore)。在linux系中,二進位訊號量(binary semaphore)又稱Mutex。

java中實現的是計數訊號量,用來控制同時訪問某個特定資源的運算元量,或者同時執行某個指定操作的數量。計數訊號量還可以用來實現某種資源集區,或者對容器施加邊界。

java中實現計數訊號量的類為java.util.concurrent.Semaphore,是在1.5中引入的。Semaphore中管理著一組許可,許可的初始數量可以通過構造方法來指定。在執行操作時需要先獲得許可(acquire),並在使用完後釋放許可(release)。如果當前沒有許可,那麼acquire將阻塞下到有許可可用,或者直到被中斷,或者操作逾時。

使用方式

使用方式可以像下面這樣:

package com.mikan.thread;import java.util.concurrent.Semaphore;/** * @author Mikan * @date 2015-08-29 18:40 */public class SemaphoreTest {    private Semaphore semaphore;    public SemaphoreTest(int permits) {        if (permits <= 0) {            throw new IllegalArgumentException("permits must be greater than 0");        }        semaphore = new Semaphore(permits);    }    public void operation() throws InterruptedException {        semaphore.acquire();        try {            // do something......        }        finally {            semaphore.release();        }    }}
Semaphore的實現是基於java.util.concurrent.locks.AbstractQueuedSynchronizer(AQS)基類,JDK中許多同步類都是基於它來實現的,像ReentrantLock、CountDownLatch、ReentrantReadWriteLock等。Semaphore的實現使用AQS的狀態來儲存許可數量,它實現了公平和非公平兩種策略,預設下是非公平策略,可以在建立Semaphore時指定公平策略。當許可為1時,可以當作互斥鎖來使用。

使用Semaphore來實現有界容器

比如這裡使用Semaphore來實現一個有指定容量的List:

package com.mikan.thread;import java.util.Collections;import java.util.LinkedList;import java.util.List;import java.util.concurrent.Semaphore;/** * @author Mikan * @date 2015-08-29 19:11 */public class BoundedList<T> {    private final List<T> list;    private final Semaphore semaphore;    public BoundedList(int bound) {        list = Collections.synchronizedList(new LinkedList<T>());        semaphore = new Semaphore(bound);    }    public boolean add(T obj) throws InterruptedException {        semaphore.acquire();        boolean addedFlag = false;        try {            addedFlag = list.add(obj);        }        finally {            if (!addedFlag) {                semaphore.release();            }        }        return addedFlag;    }    public boolean remove(Object obj) {        boolean removedFlag = list.remove(obj);        if (removedFlag) {            semaphore.release();        }        return removedFlag;    }        // 其他動作委託給底層的List,這裡只列舉出一個方法    public T get(int index) {        return list.get(index);    }        // 其他方法……}

使用訊號量來控制同時執行的線程數量
package com.mikan.thread;import java.util.concurrent.CountDownLatch;import java.util.concurrent.Semaphore;/** * @author Mikan * @date 2015-08-29 19:47 */public class BoundedThreadExecution {    public static void main(String[] args) {        final Semaphore semaphore = new Semaphore(5);        final CountDownLatch gate = new CountDownLatch(1);        int maxThreads = 100;        for (int i = 0; i < maxThreads; i++) {            final int index = i;            new Thread(new Runnable() {                @Override                public void run() {                    try {                        gate.await();                        semaphore.acquire();                        System.out.println(Thread.currentThread().getName() + "-->" + index + "--available permits=" + semaphore.availablePermits());                    } catch (InterruptedException e) {                        e.printStackTrace();                        Thread.currentThread().interrupt();                    }                    finally {                        // 不管當前線程是否正常結束,都釋放許可                        semaphore.release();                    }                }            }).start();        }        // 使用閉鎖來實現所有線程同時開始執行        gate.countDown();    }}

自己實現一個計數訊號量

package com.mikan.thread;/** * @author Mikan * @date 2015-08-29 19:19 */public class CountingSemaphore {    private final int bound;    private int permits = 0;    public CountingSemaphore(int permits) {        if (permits <= 0) {            throw new IllegalArgumentException("permits must be greater than 0");        }        this.bound = permits;    }    public synchronized void acquired() throws InterruptedException {        // 當許可達到上限時,則阻塞        while (permits == bound) {            wait();        }        permits++;    }    public synchronized void release() {        permits--;        // 釋放了許可,通知等待的線程        notifyAll();    }}

著作權聲明:本文為博主原創文章,未經博主允許不得轉載。

java中的計數訊號量(Counting Semaphore)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.