最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java并發(fā)之條件阻塞Condition的應(yīng)用代碼示例

 更新時間:2018年02月06日 09:39:13   作者:eson_15  
這篇文章主要介紹了Java并發(fā)之條件阻塞Condition的應(yīng)用代碼示例,分享了相關(guān)代碼示例,小編覺得還是挺不錯的,具有一定借鑒價值,需要的朋友可以參考下

本文研究的主要是Java并發(fā)之條件阻塞Condition的應(yīng)用示例代碼,具體如下。

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

1. Condition的基本使用

  由于Condition可以用來替代wait、notify等方法,所以可以對比著之前寫過的線程間通信的代碼來看,再來看一下原來那個問題:

有兩個線程,子線程先執(zhí)行10次,然后主線程執(zhí)行5次,然后再切換到子線程執(zhí)行10,再主線程執(zhí)行5次……如此往返執(zhí)行50次。

  之前用wait和notify來實現(xiàn)的,現(xiàn)在用Condition來改寫一下,代碼如下:

public class ConditionCommunication {
	public static void main(String[] args) {
		Business bussiness = new Business();
		new Thread(new Runnable() {
			// 開啟一個子線程
			@Override
			          public void run() {
				for (int i = 1; i <= 50; i++) {
					bussiness.sub(i);
				}
			}
		}
		).start();
		// main方法主線程
		for (int i = 1; i <= 50; i++) {
			bussiness.main(i);
		}
	}
}
class Business {
	Lock lock = new ReentrantLock();
	Condition condition = lock.newCondition();
	//Condition是在具體的lock之上的
	private Boolean bShouldSub = true;
	public void sub(int i) {
		lock.lock();
		try {
			while (!bShouldSub) {
				try {
					condition.await();
					//用condition來調(diào)用await方法
				}
				catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			for (int j = 1; j <= 10; j++) {
				System.out.println("sub thread sequence of " + j
				            + ", loop of " + i);
			}
			bShouldSub = false;
			condition.signal();
			//用condition來發(fā)出喚醒信號,喚醒某一個
		}
		finally {
			lock.unlock();
		}
	}
	public void main(int i) {
		lock.lock();
		try {
			while (bShouldSub) {
				try {
					condition.await();
					//用condition來調(diào)用await方法
				}
				catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			for (int j = 1; j <= 10; j++) {
				System.out.println("main thread sequence of " + j
				            + ", loop of " + i);
			}
			bShouldSub = true;
			condition.signal();
			//用condition來發(fā)出喚醒信號么,喚醒某一個
		}
		finally {
			lock.unlock();
		}
	}
}

從代碼來看,Condition的使用時和Lock一起的,沒有Lock就沒法使用Condition,因為Condition是通過Lock來new出來的,這種用法很簡單,只要掌握了synchronized和wait、notify的使用,完全可以掌握Lock和Condition的使用。

2. Condition的拔高

2.1 緩沖區(qū)的阻塞隊列

  上面使用Lock和Condition來代替synchronized和Object監(jiān)視器方法實現(xiàn)了兩個線程之間的通信,現(xiàn)在再來寫個稍微高級點應(yīng)用:模擬緩沖區(qū)的阻塞隊列。
什么叫緩沖區(qū)呢?舉個例子,現(xiàn)在有很多人要發(fā)消息,我是中轉(zhuǎn)站,我要幫別人把消息發(fā)出去,那么現(xiàn)在我  就需要做兩件事,一件事是接收用戶發(fā)過來的消息,并按順序放到緩沖區(qū),另一件事是從緩沖區(qū)中按順序取出用戶發(fā)過來的消息,并發(fā)送出去。

  現(xiàn)在把這個實際的問題抽象一下:緩沖區(qū)即一個數(shù)組,我們可以向數(shù)組中寫入數(shù)據(jù),也可以從數(shù)組中把數(shù)據(jù)取走,我要做的兩件事就是開啟兩個線程,一個存數(shù)據(jù),一個取數(shù)據(jù)。但是問題來了,如果緩沖區(qū)滿了,說明接收的消息太多了,即發(fā)送過來的消息太快了,我另一個線程還來不及發(fā)完,導(dǎo)致現(xiàn)在緩沖區(qū)沒地方放了,那么此時就得阻塞存數(shù)據(jù)這個線程,讓其等待;相反,如果我轉(zhuǎn)發(fā)的太快,現(xiàn)在緩沖區(qū)所有內(nèi)容都被我發(fā)完了,還沒有用戶發(fā)新的消息來,那么此時就得阻塞取數(shù)據(jù)這個線程。

  好了,分析完了這個緩沖區(qū)的阻塞隊列,下面就用Condition技術(shù)來實現(xiàn)一下:

class Buffer {
	final Lock lock = new ReentrantLock();
	//定義一個鎖
	final Condition notFull = lock.newCondition();
	//定義阻塞隊列滿了的Condition
	final Condition notEmpty = lock.newCondition();
	//定義阻塞隊列空了的Condition
	final Object[] items = new Object[10];
	//為了下面模擬,設(shè)置阻塞隊列的大小為10,不要設(shè)太大
	int putptr, takeptr, count;
	//數(shù)組下標(biāo),用來標(biāo)定位置的
	//往隊列中存數(shù)據(jù)
	public void put(Object x) throws InterruptedException {
		lock.lock();
		//上鎖
		try {
			while (count == items.length) {
				System.out.println(Thread.currentThread().getName() + " 被阻塞了,暫時無法存數(shù)據(jù)!");
				notFull.await();
				//如果隊列滿了,那么阻塞存數(shù)據(jù)這個線程,等待被喚醒
			}
			//如果沒滿,按順序往數(shù)組中存
			items[putptr] = x;
			if (++putptr == items.length) //這是到達數(shù)組末端的判斷,如果到了,再回到始端
			putptr = 0;
			++count;
			//消息數(shù)量
			System.out.println(Thread.currentThread().getName() + " 存好了值: " + x);
			notEmpty.signal();
			//好了,現(xiàn)在隊列中有數(shù)據(jù)了,喚醒隊列空的那個線程,可以取數(shù)據(jù)啦
		}
		finally {
			lock.unlock();
			//放鎖
		}
	}
	//從隊列中取數(shù)據(jù)
	public Object take() throws InterruptedException {
		lock.lock();
		//上鎖
		try {
			while (count == 0) {
				System.out.println(Thread.currentThread().getName() + " 被阻塞了,暫時無法取數(shù)據(jù)!");
				notEmpty.await();
				//如果隊列是空,那么阻塞取數(shù)據(jù)這個線程,等待被喚醒
			}
			//如果沒空,按順序從數(shù)組中取
			Object x = items[takeptr];
			if (++takeptr == items.length) //判斷是否到達末端,如果到了,再回到始端
			takeptr = 0;
			--count;
			//消息數(shù)量
			System.out.println(Thread.currentThread().getName() + " 取出了值: " + x);
			notFull.signal();
			//好了,現(xiàn)在隊列中有位置了,喚醒隊列滿的那個線程,可以存數(shù)據(jù)啦
			return x;
		}
		finally {
			lock.unlock();
			//放鎖
		}
	}
}

這個程序很經(jīng)典,我從官方JDK文檔中拿出來的,然后加了注釋。程序中定義了兩個Condition,分別針對兩個線程,等待和喚醒分別用不同的Condition來執(zhí)行,思路很清晰,程序也很健壯??梢钥紤]一個問題,為啥要用兩個Codition呢?之所以這么設(shè)計肯定是有原因的,如果用一個Condition,現(xiàn)在假設(shè)隊列滿了,但是有2個線程A和B同時存數(shù)據(jù),那么都進入了睡眠,好,現(xiàn)在另一個線程取走一個了,然后喚醒了其中一個線程A,那么A可以存了,存完后,A又喚醒一個線程,如果B被喚醒了,那就出問題了,因為此時隊列是滿的,B不能存的,B存的話就會覆蓋原來還沒被取走的值,就因為使用了一個Condition,存和取都用這個Condition來睡眠和喚醒,就亂了套。到這里,就能體會到這個Condition的用武之地了,現(xiàn)在來測試一下上面的阻塞隊列的效果:

public class BoundedBuffer {
	public static void main(String[] args) {
		Buffer buffer = new Buffer();
		for (int i = 0; i < 5; i ++) {
			//開啟5個線程往緩沖區(qū)存數(shù)據(jù)
			new Thread(new Runnable() {
				@Override
				        public void run() {
					try {
						buffer.put(new Random().nextint(1000));
						//隨機存數(shù)據(jù)
					}
					catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
			).start();
		}
		for (int i = 0; i < 10; i ++) {
			//開啟10個線程從緩沖區(qū)中取數(shù)據(jù)
			new Thread(new Runnable() {
				@Override
				        public void run() {
					try {
						buffer.take();
						//從緩沖區(qū)取數(shù)據(jù)
					}
					catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
			).start();
		}
	}
}

我故意只開啟5個線程存數(shù)據(jù),10個線程取數(shù)據(jù),就是想讓它出現(xiàn)取數(shù)據(jù)被阻塞的情況發(fā)生,看運行的結(jié)果:

Thread-5 被阻塞了,暫時無法取數(shù)據(jù)!
Thread-10 被阻塞了,暫時無法取數(shù)據(jù)!
Thread-1 存好了值: 755
Thread-0 存好了值: 206
Thread-2 存好了值: 741
Thread-3 存好了值: 381
Thread-14 取出了值: 755
Thread-4 存好了值: 783
Thread-6 取出了值: 206
Thread-7 取出了值: 741
Thread-8 取出了值: 381
Thread-9 取出了值: 783
Thread-5 被阻塞了,暫時無法取數(shù)據(jù)!
Thread-11 被阻塞了,暫時無法取數(shù)據(jù)!
Thread-12 被阻塞了,暫時無法取數(shù)據(jù)!
Thread-10 被阻塞了,暫時無法取數(shù)據(jù)!
Thread-13 被阻塞了,暫時無法取數(shù)據(jù)!

  從結(jié)果中可以看出,線程5和10搶先執(zhí)行,發(fā)現(xiàn)隊列中沒有,于是就被阻塞了,睡在那了,直到隊列中有新的值存入才可以取,但是它們兩運氣不好,存的數(shù)據(jù)又被其他線程給搶先取走了,哈哈……可以多運行幾次。如果想要看到存數(shù)據(jù)被阻塞,可以將取數(shù)據(jù)的線程設(shè)置少一點,這里我就不設(shè)了。

2.2 兩個以上線程之間的喚醒

  還是原來那個題目,現(xiàn)在讓三個線程來執(zhí)行,看一下題目:

有三個線程,子線程1先執(zhí)行10次,然后子線程2執(zhí)行10次,然后主線程執(zhí)行5次,然后再切換到子線程1執(zhí)行10次,子線程2執(zhí)行10次,主線程執(zhí)行5次……如此往返執(zhí)行50次。

  如過不用Condition,還真不好弄,但是用Condition來做的話,就非常方便了,原理很簡單,定義三個Condition,子線程1執(zhí)行完喚醒子線程2,子線程2執(zhí)行完喚醒主線程,主線程執(zhí)行完喚醒子線程1。喚醒機制和上面那個緩沖區(qū)道理差不多,下面看看代碼吧,很容易理解。

public class ThreeConditionCommunication {
	public static void main(String[] args) {
		Business bussiness = new Business();
		new Thread(new Runnable() {
			// 開啟一個子線程
			@Override
			          public void run() {
				for (int i = 1; i <= 50; i++) {
					bussiness.sub1(i);
				}
			}
		}
		).start();
		new Thread(new Runnable() {
			// 開啟另一個子線程
			@Override
			      public void run() {
				for (int i = 1; i <= 50; i++) {
					bussiness.sub2(i);
				}
			}
		}
		).start();
		// main方法主線程
		for (int i = 1; i <= 50; i++) {
			bussiness.main(i);
		}
	}
	static class Business {
		Lock lock = new ReentrantLock();
		Condition condition1 = lock.newCondition();
		//Condition是在具體的lock之上的
		Condition condition2 = lock.newCondition();
		Condition conditionMain = lock.newCondition();
		private int bShouldSub = 0;
		public void sub1(int i) {
			lock.lock();
			try {
				while (bShouldSub != 0) {
					try {
						condition1.await();
						//用condition來調(diào)用await方法
					}
					catch (Exception e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				for (int j = 1; j <= 10; j++) {
					System.out.println("sub1 thread sequence of " + j
					              + ", loop of " + i);
				}
				bShouldSub = 1;
				condition2.signal();
				//讓線程2執(zhí)行
			}
			finally {
				lock.unlock();
			}
		}
		public void sub2(int i) {
			lock.lock();
			try {
				while (bShouldSub != 1) {
					try {
						condition2.await();
						//用condition來調(diào)用await方法
					}
					catch (Exception e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				for (int j = 1; j <= 10; j++) {
					System.out.println("sub2 thread sequence of " + j
					              + ", loop of " + i);
				}
				bShouldSub = 2;
				conditionMain.signal();
				//讓主線程執(zhí)行
			}
			finally {
				lock.unlock();
			}
		}
		public void main(int i) {
			lock.lock();
			try {
				while (bShouldSub != 2) {
					try {
						conditionMain.await();
						//用condition來調(diào)用await方法
					}
					catch (Exception e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				for (int j = 1; j <= 5; j++) {
					System.out.println("main thread sequence of " + j
					              + ", loop of " + i);
				}
				bShouldSub = 0;
				condition1.signal();
				//讓線程1執(zhí)行
			}
			finally {
				lock.unlock();
			}
		}
	}
}

代碼看似有點長,但是是假象,邏輯非常簡單。關(guān)于線程中的Condition技術(shù)就總結(jié)這么多吧。

總結(jié)

以上就是本文關(guān)于Java并發(fā)之條件阻塞Condition的應(yīng)用代碼示例的全部內(nèi)容,希望對大家有所幫助。感興趣的朋友可以繼續(xù)參閱本站其他相關(guān)專題,如有不足之處,歡迎留言指出。感謝朋友們對本站的支持!

相關(guān)文章

  • Java HttpClient技術(shù)詳解

    Java HttpClient技術(shù)詳解

    Http協(xié)議的重要性相信不用我多說了,HttpClient相比傳統(tǒng)JDK自帶的URLConnection,增加了易用和靈活性(具體區(qū)別,日后我們再討論),它不僅是客戶端發(fā)送Http請求變得容易,而且也方便了開發(fā)人員測試接口(基于Http協(xié)議的),即提高了開發(fā)的效率,也方便提高代碼的健壯性
    2021-10-10
  • Java的編譯時錯誤和運行時錯誤問題

    Java的編譯時錯誤和運行時錯誤問題

    這篇文章主要介紹了Java的編譯時錯誤和運行時錯誤問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-04-04
  • Java實用技巧:如何使用String去除開頭的第一個字符?

    Java實用技巧:如何使用String去除開頭的第一個字符?

    這篇文章主要介紹了Java實用技巧:如何使用String去除開頭的第一個字符,需要的朋友可以參考下
    2023-11-11
  • Spring?Boot騰訊云短信申請與使用示例

    Spring?Boot騰訊云短信申請與使用示例

    這篇文章主要介紹了Spring?Boot騰訊云短信申請與使用,本文通過實例代碼圖文相結(jié)合給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-12-12
  • 使用Springboot自定義轉(zhuǎn)換器實現(xiàn)參數(shù)去空格功能

    使用Springboot自定義轉(zhuǎn)換器實現(xiàn)參數(shù)去空格功能

    這篇文章主要介紹了使用Springboot自定義轉(zhuǎn)換器實現(xiàn)參數(shù)去空格功能,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • 使用Java8實現(xiàn)模板方法模式的改造

    使用Java8實現(xiàn)模板方法模式的改造

    這篇文章主要為大家詳細介紹了如何使用Java8實現(xiàn)模板方法模式的改造,文中的示例代碼講解詳細,對我們深入了解java8有一定的幫助,感興趣的可以了了解一下
    2023-01-01
  • Java報NoClassDefFoundError異常的原因及解決

    Java報NoClassDefFoundError異常的原因及解決

    在 Java 開發(fā)過程中, java.lang.NoClassDefFoundError 是一個令人頭疼的運行時錯誤,本文將深入探討這一問題的原因和常見場景,并提供實用的解決方法,希望對大家有所幫助
    2025-03-03
  • IDEA中如何引入spring的命名空間

    IDEA中如何引入spring的命名空間

    這篇文章主要介紹了IDEA中如何引入spring的命名空間問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-04-04
  • 利用Jackson解決Json序列化和反序列化問題

    利用Jackson解決Json序列化和反序列化問題

    Jackson是一個用于處理Json數(shù)據(jù)的Java庫,它提供了一系列功能,包括Json序列化和反序列化,所以本文就來講講如何利用利用Jackson解決Json序列化和反序列化的問題吧
    2023-05-05
  • Java 反轉(zhuǎn)帶頭結(jié)點的單鏈表并顯示輸出的實現(xiàn)過程

    Java 反轉(zhuǎn)帶頭結(jié)點的單鏈表并顯示輸出的實現(xiàn)過程

    這篇文章主要介紹了Java 反轉(zhuǎn)帶頭結(jié)點的單鏈表并顯示輸出,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-11-11

最新評論

霍城县| 九江县| 阳泉市| 南漳县| 祁门县| 芮城县| 衢州市| 平乐县| 平陆县| 定远县| 新乡县| 甘谷县| 长岭县| 奉新县| 资源县| 县级市| 乐山市| 合阳县| 垣曲县| 宣武区| 磴口县| 务川| 进贤县| 眉山市| 循化| 从化市| 乐山市| 休宁县| 日喀则市| 齐齐哈尔市| 道孚县| 招远市| 盱眙县| 玛曲县| 隆回县| 麦盖提县| 曲松县| 宁晋县| 深圳市| 永胜县| 信丰县|