轉載地址:http://blog.csdn.net/wxwzy738/article/details/8522493
JDK原話,假定有一個綁定的緩衝區,它支持 put 和 take 方法。如果試圖在空的緩衝區上執行 take 操作,則在某一個項變得可用之前,線程將一直阻塞;如果試圖在滿的緩衝區上執行 put 操作,則在有空間變得可用之前,線程將一直阻塞。我們喜歡在單獨的等待 set 中保存 put 線程和 take 線程,這樣就可以在緩衝區中的項或空間變得可用時利用最佳規劃,一次只通知一個線程。可以使用兩個 Condition 實例來做到這一點。
這裏爲什麼要寫上notFull和notEmpty,而不是直接使用一個變量來進行操作,因爲兩個notFull和notEmpty分別控制生產線程和消費線程,這樣在喚醒的時候就會喚醒其中一類線程,如果只有一個實例的話那會喚醒阻塞隊列中的一個線程,那麼會讓兩類線程都進行爭奪資源
- import java.util.concurrent.locks.Condition;
- import java.util.concurrent.locks.Lock;
- import java.util.concurrent.locks.ReentrantLock;
- //有限緩存使用顯示的條件變量,
- public class ConditionBoundedBuffer<T> {
- protected final Lock lock = new ReentrantLock();
- //條件謂詞,notFull(count < items.length)
- private final Condition notFull = lock.newCondition();
- //條件謂詞,notEmpty(count > 0)
- private final Condition notEmpty = lock.newCondition();
- private final int BUFFER_SIZE = 10;
- //基於隊列的循環緩存
- private final T[] items = (T[])new Object[BUFFER_SIZE];
- private int tail,head,count;
- //阻塞,直到:notFull
- public void put(T x) throws InterruptedException{
- lock.lock();
- try{
- while(count == items.length){
- notFull.await();//這個對象鎖是lock,而非是調用該方法的對象了,如果不使用lock.lock(),而直接在該方法上加上synchronized會拋出異常
- }
- items[tail] = x;
- if(++tail == items.length){
- tail = 0;
- }
- ++count;
- notEmpty.signal();
- }finally{
- lock.unlock();
- }
- }
- //阻塞,直到:notEmpty
- public T take() throws InterruptedException{
- lock.lock();
- try{
- while(count == 0){
- notEmpty.await();
- }
- T x = items[head];
- items[head] = null;
- if(++head == items.length){
- head = 0;
- }
- --count;
- notFull.signal();
- return x;
- }finally{
- lock.unlock();
- }
- }
- }
- import java.util.concurrent.locks.Condition;
- import java.util.concurrent.locks.Lock;
- import java.util.concurrent.locks.ReentrantLock;
- //使用lock實現的計數信號量
- //這並不是Semaphore的真正實現,而是繼承AbstractQueuedSynchronizer實現的
- public class SemaphoreOnLock {
- private final Lock lock = new ReentrantLock();
- //條件謂詞:permitsAvailable (permits > 0)
- private final Condition permitsAvailable = lock.newCondition();
- private int permits;
- SemaphoreOnLock(int initialPermits){
- lock.lock();
- try{
- permits = initialPermits;
- }finally{
- lock.unlock();
- }
- }
- //阻塞,直到:permitsAvailable
- public void acquire() throws InterruptedException{
- lock.lock();
- try{
- while(permits <= 0){
- permitsAvailable.await();
- }
- --permits;
- }finally{
- lock.unlock();
- }
- }
- public void release(){
- lock.lock();
- try{
- ++permits;
- permitsAvailable.signal();
- }finally{
- lock.unlock();
- }
- }
- }
- import java.util.concurrent.TimeUnit;
- public class SemaphoreTest implements Runnable{
- SemaphoreOnLock sema = new SemaphoreOnLock(3);
- public static void main(String[] args) {
- SemaphoreTest test = new SemaphoreTest();
- for(int i=0; i<10; i++){
- new Thread(test).start();
- }
- }
- @Override
- public void run() {
- test();
- }
- private void test() {
- try {
- sema.acquire();
- } catch (InterruptedException e1) {
- e1.printStackTrace();
- }
- for(int i=1; i<=3; i++){
- System.out.println(Thread.currentThread().getName()+"#執行:"+i);
- try {
- TimeUnit.SECONDS.sleep(1);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- sema.release();
- }
- /**
- * 運行結果:
- * 當前還有3個許可..
- 當前還有2個許可..
- Thread-2#執行:1
- 當前還有1個許可..
- Thread-3#執行:1
- Thread-0#執行:1
- Thread-2#執行:2
- Thread-0#執行:2
- Thread-3#執行:2
- Thread-2#執行:3
- Thread-0#執行:3
- Thread-3#執行:3
- 當前還有2個許可..
- Thread-5#執行:1
- 當前還有1個許可..
- Thread-7#執行:1
- 當前還有1個許可..
- Thread-9#執行:1
- Thread-5#執行:2
- Thread-7#執行:2
- Thread-9#執行:2
- */
- }