java併發編程(10)--Condition

1.如何得到Condition

在Lock中

 Condition newCondition()
          返回綁定到此 Lock 實例的新 Condition 實例。

2.使用Condition進行線程之間的通信 改進傳統的線程之間同信代碼

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

/**
 * 子線程循環10次 主線程循環100次 如此交替 50次
 * 
 * @author hao.su
 * 
 */
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();
		boolean bShouldSub = true;

		public  void sub(int i) {
			lock.lock();
			try {
				while (!bShouldSub) {// 用while防止未喚醒
					try {
						condition.await();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				for (int j = 0; j < 10; j++) {
					System.out.println("sub thread sequence of" + j
							+ ",loop of" + i);
				}
				
			} catch (Exception e) {
				
			}finally{
				lock.unlock();
			}
		}

		public  void main(int i) {
			lock.lock();
			try {
				while (bShouldSub) {
					try {
						condition.await();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				for (int j = 0; j < 100; j++) {
					System.out.println("main thread sequence of" + j
							+ ",loop of" + i);
				}
				bShouldSub = true;
				condition.signal();
			} catch (Exception e) {
				e.printStackTrace();
			}finally{
				lock.unlock();
			}
		}
	}
}
  在等待Condition時,允許發生虛假喚醒,這通常作爲基礎平臺語義的讓步,對於大多數應用程序,這帶來的實際影響很小,因爲Condition總應該在一個循環中等待,並測試正被等待的狀態聲明,某個實現可以隨意移除可能的虛假喚醒,但建議應用程序程序員總是假定這些虛假喚醒可能發生,因此總是在一個循環中等待。
  一個鎖內部可以有多個Condition,即有多路等待通知,可以參考一下jdk中Lock和Condition實現可阻塞隊列的案例

jdk幫助文檔這樣寫道:

Condition 實例實質上被綁定到一個鎖上。要爲特定 Lock 實例獲得 Condition 實例,請使用其 newCondition() 方法。

作爲一個示例,假定有一個綁定的緩衝區,它支持 puttake 方法。如果試圖在空的緩衝區上執行 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();
     }
   }

但是ArrayBlockingQueue類提供了這項功能,因此沒有必要去實現該項功能



4.實現功能,當A執行完畢後執行B之後執行C  c執行之後執行A 如此循環

package com.qunar.thread;

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

/**
 * 子線程循環10次 主線程循環100次 如此交替 50次
 * 
 * @author hao.su
 * 
 */
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 < 50; i++) {
					business.sub2(i);
				}
			}
		}).start();

		new Thread(new Runnable() {
			public void run() {
				for (int i = 0; i < 50; i++) {
					business.sub3(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();
		int iShouldSub = 1;

		public void sub2(int i) {
			lock.lock();
			try {
				while (iShouldSub != 2) {// 用while防止未喚醒
					try {
						condition2.await();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				for (int j = 0; j < 10; j++) {
					System.out.println("sub2 thread sequence of" + j
							+ ",loop of" + i);
				}
				iShouldSub = 3;
				condition3.signal();
			} catch (Exception e) {

			} finally {
				lock.unlock();
			}
		}

		public void sub3(int i) {
			lock.lock();
			try {
				while (iShouldSub!=3) {// 用while防止未喚醒
					try {
						condition3.await();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				for (int j = 0; j < 10; j++) {
					System.out.println("sub3 thread sequence of" + j
							+ ",loop of" + i);
				}
				iShouldSub = 1;
				condition1.signal();
			} catch (Exception e) {

			} finally {
				lock.unlock();
			}
		}

		public void main(int i) {
			lock.lock();
			try {
				while (iShouldSub!=1) {
					try {
						condition1.await();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				for (int j = 0; j < 100; j++) {
					System.out.println("main thread sequence of" + j
							+ ",loop of" + i);
				}
				iShouldSub = 2;
				condition2.signal();
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				lock.unlock();
			}
		}
	}
}



發佈了93 篇原創文章 · 獲贊 1 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章