多執行緒與併發-----條件阻塞Condition的應用

pengzhisen123發表於2018-05-13

Condition

   1、 功能:

        其類似在傳統執行緒技術中的 Object.wait() 和 Object.notify() 的功能,傳統執行緒技術實現互斥只能是一個執行緒單獨幹,不能說這個執行緒幹完了通知另一個執行緒來幹,Condition就是解決這個問題:實現執行緒間的通訊。比如CPU讓小弟做事,小弟說我先歇著,並通知大哥,大哥開始做事。

    public interface Condition

    Condition 將 Object監視器方法(wait、notify和notifyAll)分解成截然不同的物件,以便通過將這些物件與任意Lock實現組合使用,為每個物件提供多個等待set(wait-set)。其中,Lock替代了 synchronized 方法和語句的使用,Condition替代了 Object 監視器方法的使用。

  2、 實質:

        實質上是被繫結到一個鎖上。要為特定的 Lock 例項獲得 Condition 例項,請使用 new Condition()方法。

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ConditionCommunication {

	public static void main(String[] args) {
		
		final Business business=new Business();
		
		new Thread(new Runnable() {
			
			public void run() {
				for(int i=0;i<50;i++){	
						business.sub(i);
				}
				
			}
			
		}).start();
		
		for(int i=0;i<50;i++){
			business.main(i);
		}
	}
	
	static class Business{
		Lock lock=new ReentrantLock();
		Condition condition=lock.newCondition();
		private boolean bSholdSub=true;
		public void sub(int i){
			lock.lock();
			try{
				while(!bSholdSub){
					try {
						//this.wait();
						condition.await();
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
				
				for(int j=0;j<10;j++){
					System.out.println("sub thread sequence of"+j+",loop of"+i);
				}
				bSholdSub=false;
				condition.signal();
				//this.notify();//notify必須和synchronized一起用
			}finally{
				lock.unlock();
			}
			
		}
		
		public void main(int i){
			lock.lock();
			try{
				while(bSholdSub){
					try {
						//this.wait();
						condition.await();
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
				for(int j=0;j<10;j++){
					System.out.println("main thread sequence of"+j+",loop of"+i);
				}
				bSholdSub=true;
				//this.notify();
				condition.signal();
			}finally{
				lock.unlock();
			}
		}
	}

}

        執行結果為:

sub thread sequence of0,loop of0
sub thread sequence of1,loop of0
sub thread sequence of2,loop of0
sub thread sequence of3,loop of0
sub thread sequence of4,loop of0
sub thread sequence of5,loop of0
sub thread sequence of6,loop of0
sub thread sequence of7,loop of0
sub thread sequence of8,loop of0
sub thread sequence of9,loop of0
main thread sequence of0,loop of0
main thread sequence of1,loop of0
main thread sequence of2,loop of0
main thread sequence of3,loop of0
main thread sequence of4,loop of0
main thread sequence of5,loop of0
main thread sequence of6,loop of0
main thread sequence of7,loop of0
main thread sequence of8,loop of0
main thread sequence of9,loop of0

    

3、例項---可阻塞佇列

假定有一個繫結的緩衝區,它支援 put 和 take 方法。如果試圖在空的緩衝區上執行 take 操作,則在某一個項變得可用之前,執行緒將一直阻塞;如果試圖在滿的緩衝區上執行 put 操作,則在有空間變得可用之前,執行緒將一直阻塞。我們喜歡在單獨的等待 set 中儲存 put 執行緒和 take 執行緒,這樣就可以在緩衝區中的項或空間變得可用時利用最佳規劃,一次只通知一個執行緒。可以使用兩個 Condition 例項來做到這一點。

 class BoundedBuffer {阻塞佇列 滿了不能放,空了不能取
   final Lock lock = new ReentrantLock();
   final Condition notFull  = lock.newCondition(); 
   final Condition notEmpty = lock.newCondition(); 

   final Object[] items = new Object[100];
   int putptr, takeptr, count;

   public void put(Object x) throws InterruptedException {
     lock.lock();
     try {
       while (count == items.length) 
         notFull.await();
       items[putptr] = x; 
       if (++putptr == items.length) putptr = 0;
       ++count;
       notEmpty.signal();
     } finally {
       lock.unlock();
     }
   }

   public Object take() throws InterruptedException {
     lock.lock();
     try {
       while (count == 0) 
         notEmpty.await();
       Object x = items[takeptr]; 
       if (++takeptr == items.length) takeptr = 0;
       --count;
       notFull.signal();
       return x;
     } finally {
       lock.unlock();
     }
   } 
 }


        使用方法:

                Lock lock = new ReentrantLock();

                Condition condition = lock.newCondition();

                this.wait()----》condition.await()

                this.notify()----》condition.signal()

注意:判斷條件時用while防止虛假喚醒,等待在那裡,喚醒後再進行判斷,確認符合要求後再執行任務。


例項:

   有三個執行緒,主執行緒10次,第一個子執行緒10次,第二個子執行緒10次迴圈執行50次。用Condition方法實現

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ThreeConditionCommunication {

	public static void main(String[] args) {
		
		final Business business=new Business();
		
		new Thread(new Runnable() {
			
			public void run() {
				for(int i=0;i<10;i++){	
						business.sub1(i);
				}
				
			}
			
		}).start();
		new Thread(new Runnable() {
			
			public void run() {
				for(int i=0;i<20;i++){	
						business.sub2(i);
				}
				
			}
			
		}).start();
		
		for(int i=0;i<50;i++){
			business.main(i);
		}
	}
	
	static class Business{
		Lock lock=new ReentrantLock();
		Condition condition1=lock.newCondition();
		Condition condition2=lock.newCondition();
		Condition condition3=lock.newCondition();
		
		//private boolean bSholdSub=true;
		private int shouldsub=1;
		public void sub1(int i){
			lock.lock();
			try{
				while(shouldsub!=2){
					try {
						//this.wait();
						condition2.await();
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
				
				for(int j=0;j<10;j++){
					System.out.println("sub1 thread sequence of"+j+",loop of"+i);
				}
				//bSholdSub=false;
				//condition.signal();
				
				shouldsub=3;
				condition3.signal();
				
				//this.notify();//notify必須和synchronized一起用
			}finally{
				lock.unlock();
			}
			
		}
		
		public void sub2(int i){
			lock.lock();
			try{
				while(shouldsub!=3){
					try {
						//this.wait();
						condition3.await();
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
				
				for(int j=0;j<10;j++){
					System.out.println("sub2 thread sequence of"+j+",loop of"+i);
				}
				/*bSholdSub=false;
				condition.signal();*/
				
				shouldsub=1;
				condition1.signal();
				
				//this.notify();//notify必須和synchronized一起用
			}finally{
				lock.unlock();
			}
			
		}
		
		public void main(int i){
			lock.lock();
			try{
				while(shouldsub!=1){
					try {
						//this.wait();
						condition1.await();
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
				for(int j=0;j<10;j++){
					System.out.println("main thread sequence of"+j+",loop of"+i);
				}
				/*bSholdSub=true;
				//this.notify();
				condition.signal();*/
				
				shouldsub=2;
				condition2.signal();
				
			}finally{
				lock.unlock();
			}
		}
	}

}

執行結果為:

main thread sequence of0,loop of0
main thread sequence of1,loop of0
main thread sequence of2,loop of0
main thread sequence of3,loop of0
main thread sequence of4,loop of0
main thread sequence of5,loop of0
main thread sequence of6,loop of0
main thread sequence of7,loop of0
main thread sequence of8,loop of0
main thread sequence of9,loop of0
sub1 thread sequence of0,loop of0
sub1 thread sequence of1,loop of0
sub1 thread sequence of2,loop of0
sub1 thread sequence of3,loop of0
sub1 thread sequence of4,loop of0
sub1 thread sequence of5,loop of0
sub1 thread sequence of6,loop of0
sub1 thread sequence of7,loop of0
sub1 thread sequence of8,loop of0
sub1 thread sequence of9,loop of0
sub2 thread sequence of0,loop of0
sub2 thread sequence of1,loop of0
sub2 thread sequence of2,loop of0
sub2 thread sequence of3,loop of0
sub2 thread sequence of4,loop of0
sub2 thread sequence of5,loop of0
sub2 thread sequence of6,loop of0
sub2 thread sequence of7,loop of0
sub2 thread sequence of8,loop of0

sub2 thread sequence of9,loop of0

......

相關文章