1. 程式人生 > >JAVA多執行緒-執行緒間通訊(一)-等待/通知機制(wait/notify)

JAVA多執行緒-執行緒間通訊(一)-等待/通知機制(wait/notify)

執行緒間通訊

    執行緒與執行緒之間不是獨立的個體,它們彼此之間可以相互通訊與協作。

    執行緒間通訊後,系統之間的互動性會更強大,在大大提交CPU利用率的同時,還會使程式要對各執行緒任務在處理的過程中進行有效的把控和監督。

    學習目錄:

    一、使用wait/notify實現執行緒間的通訊

    二、生產者/消費者模式的實現

    三、方法join的使用

    四、ThreadLocal類的使用


    一、使用wait/notify實現執行緒間的通訊

       1.1 不使用等待/通知機制實現執行緒間通訊:

             執行緒A做i++的操作,執行緒B利用while(true){if(i==5){to do ...}}輪詢去檢測 i 的值,這樣會非常浪費CPU資源。

             如果輪詢時間間隔較短,更浪費CPU資源;如果輪詢時間間隔較長,有可能會取不奧想要得到的資料。

             所以,就需要一種機制來減少CPU的資源浪費,而且還可以實現在多個執行緒間通訊,它就是“wait/notify”機制。

       1.2 等待/通知機制的實現】

            方法wait()的作用是使當前執行程式碼的執行緒進行等待,wait()方法是Object類的方法,該方法是用來將當前執行緒置入“預執行佇列”中,並且在wait()所在的程式碼處停止執行,知道接到通知或被中斷為止。

            wait()方法只能在同步方法中或同步塊中呼叫。如果呼叫wait()時,沒有持有適當的鎖,會丟擲異常。

            wait()方法執行後,當前執行緒釋放鎖,執行緒與其他執行緒競爭重新獲取鎖。

            方法notify()也要在同步方法或同步塊中呼叫,該方法是用來通知那些可能等待該物件的物件鎖的其他執行緒,對其發出通知notify,並使它重新獲取該物件的物件鎖。如果有多個執行緒等待,則有執行緒規劃器隨機挑選出一個呈wait狀態的執行緒。

           在notify()方法後,當前執行緒不會馬上釋放該物件鎖,要等到執行notify()方法的執行緒將程式執行完,也就是退出同步程式碼塊中。

             小結一下:wait()是使執行緒停止執行,而notify使停止的執行緒繼續執行。

        簡單案例

        程式碼清單:

<span style="font-size:18px;">package org.jksoft.thread.Volatile;
/**
 * 測試三:使用wait/notify機制的案例
 * 注意:wait/notify都必須在同步程式碼塊中呼叫。
 * @author mcl
 *
 * 2016-2-20-下午12:01:25
 */
public class Test3 {
	public static void main(String[] args) throws InterruptedException {
		Object lock = new Object();
		MyThread1 t1 = new MyThread1(lock);
		t1.start();
		Thread.sleep(3000);
		MyThread2 t2 = new MyThread2(lock);
		t2.start();
	}
}
class MyThread1 extends Thread{
	private Object lock;
	public MyThread1(Object lock){
		this.lock = lock;
	}
	@Override
	public void run(){
			try {
				synchronized (lock) {
				System.out.println("begin wait   "+System.currentTimeMillis());
				lock.wait();
				System.out.println("end wait     "+System.currentTimeMillis());
				}
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		
	}
}
class MyThread2 extends Thread{
	private Object lock;
	public MyThread2(Object lock){
		this.lock = lock;
	}
	@Override
	public void run(){
		synchronized (lock) {
				System.out.println("begin notify "+System.currentTimeMillis());
				lock.notify();
				System.out.println("end notify   "+System.currentTimeMillis());
		}
	}
}</span>
         案例結果:3秒後,喚醒處於wait等待的執行緒。

 

       Java為每一個Object都實現了wait()和notify()方法,他們必須用於同步程式碼塊內。

        notify()方法可以隨機喚醒等待佇列中等待同一共享資源的“一個執行緒”,並使該執行緒退出等待佇列,進入可執行狀態,也就是notify()方法僅通知“一個“執行緒。

       notifyAll()方法可以使所有正在等待佇列中等待同一資源的"全部"執行緒從等待狀態中退出,進入可執行狀態。

      1.3 方法wait()鎖釋放與notify()鎖不釋放。

      1.4 當interrupt方法遇到wait方法

            當執行緒呈wait狀態時,呼叫執行緒物件的interrupt()方法會出現異常。

      1.5  方法wait(long)的使用

            帶一個引數的wait(long)方法的功能是等待某一個時間內是否有執行緒對鎖進行喚醒,如果超過這個時間則自動喚醒。

     1.6 等待wait的條件發生變化

      案例:執行緒r1,r2負責向list集合中移除一個元素,如果list的size為0,則進入堵塞佇列

                 執行緒a負責向list集合中新增一個元素,然後喚醒所有等待在堵塞佇列的所有執行緒。

      程式碼清單:

package org.jksoft.thread.Volatile;

import java.util.ArrayList;
import java.util.List;

/**
 * 測試四:使用wait/notify機制的案例,當wait的等待條件發生改變時 注意:wait/notify都必須在同步程式碼塊中呼叫。
 * 
 * @author mcl
 * 
 *         2016-2-20-下午12:01:25
 */
public class Test4 {
	private static List<String> list = new ArrayList<String>();
	
	public static void main(String[] args) throws InterruptedException {
		String lock = "";
		removeThread r1 = new removeThread(lock);
		r1.start();
		removeThread r2 = new removeThread(lock);
		r2.start();
		Thread.sleep(3000);
		addThread a = new addThread(lock);
		a.start();
	}
	static class addThread extends Thread {
		private String lock;
		public addThread(String lock) {
			this.lock = lock;
		}
		public void run() {
			synchronized (lock) {
				list.add("a");
				lock.notifyAll();
				System.out.println("喚醒所有等待該鎖的執行緒");
			}

		}
	}
	static class removeThread extends Thread {
		private String lock;
		public removeThread(String lock) {
			this.lock = lock;
		}
		public void run() {
			try {
				synchronized (lock) {
					if (list.size() == 0) {
						System.out.println("進入等待喚醒的佇列..."
								+ Thread.currentThread().getName());
						lock.wait();
						System.out.println("等待佇列的執行緒被喚醒..."
								+ Thread.currentThread().getName());
					}
					list.remove(0);
				}
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		}
	}
}
        執行結果:

 

        執行結果分析:

         剛開始的時候,list的size為0,所以兩個r執行緒進入堵塞佇列。等到a執行緒向list集合中新增一個元素後,喚醒了r1,r2兩個執行緒。兩個執行緒都去繼續向下執行,都進行list.remove(0)的運算,那麼這樣的話,只有一個元素的list是不能移出兩個的,所以只能丟擲異常。

        問題出現原因:是由於r1,r2兩個執行緒沒有重新去驗證list的size的條件,導致後續結果的異常。

        解決方案:

            將上訴程式碼中,

if (list.size() == 0) {
更改為
while (list.size() == 0) { 

         我們再看一下執行結果:這就與我們所期待的結果一致了。

 

相關推薦

JAVA執行-執行通訊()-等待/通知機制wait/notify

執行緒間通訊     執行緒與執行緒之間不是獨立的個體,它們彼此之間可以相互通訊與協作。     執行緒間通訊後,系統之間的互動性會更強大,在大大提交CPU利用率的同時,還會使程式要對各執行緒任務在處

java執行等待喚醒機制wait-notify

wait()、notify()、notifyAll()方法 Object類裡面提供了這幾個方法: wait():讓當前執行緒處於等待(阻塞狀態),直到其他執行緒呼叫此物件的notify()或noti

Java併發程式設計(04):執行通訊等待/通知機制

本文原始碼:[GitHub·點這裡](https://github.com/cicadasmile/java-base-parent) || [GitEE·點這裡](https://gitee.com/cicadasmile/java-base-parent) # 一、概念簡介 ## 1、執行緒通訊

執行通訊_等待/通知之Thread.join()

Thread.join原始碼:public final synchronized void join(long millis) throws InterruptedException {

執行通訊等待喚醒機制、生產者消費者問題(Lock,Condition)、停止執行和守護執行執行優先順序

1  執行緒間通訊 1.1  執行緒間通訊 其實就是多個執行緒在操作同一個資源,但是操作的動作不同。 比如一個執行緒給一個變數賦值,而另一個執行緒列印這個變數。 1.2  等待喚醒機制 wait():將執行緒等待,釋放了CPU執行權,同時將執行緒物件儲存到執行緒池中。 n

java 執行通知和掛起處理 wait/notify

public class ThreadWaitNotifyTest{ private boolean flag = true; private void test(){ Object lock = new Object(); T

執行程式設計》學習之七:等待/通知機制

         今天起開始學習執行緒之間的通訊。等待/通知機制是通過Object類的wait()與notify()方法來實現的,這兩個方法在同步方法或同步程式碼塊中才能被執行。wait()方法將當前執行緒放入“等待執行佇列”中,使執行緒在wait()方法所處程式碼處停止執

執行程式設計》學習之七:等待/通知機制

1、生產者與消費者問題           利用等待/通知機制,實現一生產與一消費:操作棧。生產者向棧中生產資料,消費者從棧中消費資料,棧的最大容量為1。           可見容器的size不會大於1,生產與消費這兩個過程交替進行。 2、通過管道進行執行緒之間的

Java執行等待/通知wait/notify機制詳解

Java的等待/通知 機制,舉例來說就是,執行緒A,拿到了物件object的鎖,並且呼叫了object的wait()方法,同時釋放了鎖,然後進入WAITTING狀態。執行緒B同樣前提是拿到了object的鎖,然後呼叫了notify()或notifyAll()方法

線程一共就倆問題:1.線程安全訪問共享數據 2.線程通信wait(),notify()

class 共享 問題 無法 not 安全 pos 三方 gpo 多線程一共就倆問題:1.線程安全(訪問共享數據) 2.線程通信(wait(),notify()) 1.線程安全,無非就是加鎖,訪問共享資源時,synchronized 2.線程通信,就是控制各個線程之間的

Java的阻塞和中斷機制 wait notify使用 wait和sleep區別 interrupt使用和其他中斷方法

wait、notify和notifyAll wait和notify(notifyAll)一般是成對搭配出現的,用來資源調控。wait用來將當然執行緒掛起,notify/notifyAll用來恢復執行緒。它是類Object的方法,也就是所有的物件都可以使用。一個簡單的例子

Java 執行通訊 —— 等待 / 通知機制

> 本文部分摘自《Java 併發程式設計的藝術》 ## volatile 和 synchronize 關鍵字 每個處於執行狀態的執行緒,如果僅僅是孤立地執行,那麼它產生的作用很小,如果多個執行緒能夠相互配合完成工作,則將帶來更大的價值 Java 支援多個執行緒同時訪問一個物件或者物件的成員變數,

Java執行程式設計實戰》—— 第8章 Active Object主動物件模式

Active Object模式是一種非同步程式設計模式。(跟Promise模式有什麼區別呢?) 通過對方法的呼叫與方法的執行進行解耦來提高併發性。 類圖 當Active Object模式對外暴露的非同步方法被呼叫時,與該方法呼叫相關的上下文資訊,包括被呼叫的非同步方法名、引數等,會被

python中執行中event的使用-----------------即一個靈活的方法標誌位,類似於java等待喚醒機制python與java不同的地方

event是python中一個特有的標誌位方法,他一共有三種方法 1.event.wait():如果標誌位設定了,它不做任何事,如果沒有設定,則將會鎖住,等待標誌位的設定 2.event.set():設定標誌位 3.event.clear():清除標誌位 這一種機制很

Java執行之三volatile與等待通知機制示例

原子性,可見性與有序性 在多執行緒中,執行緒同步的時候一般需要考慮原子性,可見性與有序性 原子性 原子性定義:一個操作或者多個操作在執行過程中要麼全部執行完成,要麼全部都不執行,不存在執行一部分的情況。 以我們在Java程式碼中經常用到的自增操作i++為例,i++實際上並不是一步操作,而是首先對i的值加一,然

java執行之間的通訊(等待/通知機制)

執行緒開始執行,擁有自己的棧空間,就如同一個指令碼一樣,按照程式碼一步步的執行直到終止。但是,每個執行中的執行緒,如果僅僅是孤立地執行,那麼沒有太大的價值,但如果多個執行緒能夠相互配合完成工作,這將會帶來巨大的價值。 而java多執行緒的等待和通知機制就是用來

java執行等待/通知機制

一個執行緒做了修改物件值(或其他)操作,另一個執行緒感知到了變化,然後進行相應操作,整個過程開始於一個執行緒,最終執行又是另外一個執行緒。前者是生產者,後者是消費者,這種模式隔離了“做什麼”和“怎麼做”,實現了業務上的解耦。 其具體實現方式是執行緒A呼叫了物件O的wait(

後臺開發:核心技術與應用實踐--執行與程序通訊

## 多執行緒 程序在多數早期多工作業系統中是執行工作的基本單元。程序是包含程式指令和相關資源的集合,每個程序和其他程序一起參與排程,競爭 CPU 、記憶體等系統資源。每次程序切換,都存在程序資源的儲存和恢復動作,這稱為上下文切換。程序的引入可以解決多使用者支援的問題,但是多程序系統也在如下方面產生了新的問

執行等待喚醒機制-

執行緒間的同步 等待喚醒機制 執行緒的wait()方法使用就是放棄了執行資格 等待的執行緒都存線上程池當中。 方法:只能在現場同步當中使用。下面的方法必須強調監視器 wait();// 可以是當前執行緒進行等待 notify();// 喚醒

執行之間的通訊wait()/notify()機制——等待喚醒機制

wait() : 使當前同步監視器上的執行緒進入等待狀態, 同時釋放鎖     物件名.wait()notify() / notifyAll() : 喚醒當前同步監視器上等待狀態的一個(所有)執行緒    物件名.notify()-------------------- 上述