JAVA多線程通信

一、兩個線程間的通信

1.什麼時候需要通信

多個線程併發執行時,在默認情況下CPU是隨機切換線程的,如果我們希望他們有規律的執行, 就可以使用通信, 例如每個線程執行一次打印

2.如何通信

如果希望線程等待,就調用wait()

如果希望喚醒等待的線程,就調用notify()

這兩個方法必須在同步代碼中執行, 並且使用同步鎖對象來調用

3.代碼

class Printer {
	private int flag = 1;
	public void print1() throws InterruptedException {
		synchronized(this) {
			if(flag != 1) {
				this.wait();				//當前線程等待
			}
			System.out.print("1");
			System.out.print("2");
			System.out.print("3");
			System.out.print("4");
			System.out.print("5");
			System.out.print("\r\n");
			flag = 2;
			this.notify();				//隨機喚醒單個等待的線程
		}
	}
	
	public void print2() throws InterruptedException {
		synchronized(this) {
			if(flag != 2) {
				this.wait();
			}
			System.out.print("a");
			System.out.print("b");
			System.out.print("c");
			System.out.print("d");
			System.out.print("\r\n");
			flag = 1;
			this.notify();
		}
	}
}

二、三個及以上線程間的通信

1.如何通信

notify()方法是隨機喚醒一個線程,notifyAll()方法是喚醒所有線程

JDK5之前無法喚醒指定的一個線程,如果多個線程之間通信,需要使用notifyAll()通知所有線程,用while來反覆判斷條件

2.代碼

class Printer2 {
	private int flag = 1;
	public void print1() throws InterruptedException {
		synchronized(this) {
			while(flag != 1) {
				this.wait();				
			}
			System.out.print("黑");
			System.out.print("馬");
			System.out.print("程");
			System.out.print("序");
			System.out.print("員");
			System.out.print("\r\n");
			flag = 2;
			this.notifyAll();
		}
	}
	
	public void print2() throws InterruptedException {
		synchronized(this) {
			while(flag != 2) {
				this.wait();					//線程2在此等待
			}
			System.out.print("傳");
			System.out.print("智");
			System.out.print("播");
			System.out.print("客");
			System.out.print("\r\n");
			flag = 3;
			this.notifyAll();
		}
	}
	
	public void print3() throws InterruptedException {
		synchronized(this) {
			while(flag != 3) {
				this.wait();	//線程3在此等待,if語句是在哪裏等待,就在哪裏起來
								//while循環是循環判斷,每次都會判斷標記
			}
			System.out.print("i");
			System.out.print("t");
			System.out.print("h");
			System.out.print("e");
			System.out.print("i");
			System.out.print("m");
			System.out.print("a");
			System.out.print("\r\n");
			flag = 1;
			this.notifyAll();
		}
	}
}

注:

  • 1.在同步代碼塊中,用哪個對象鎖,就用哪個對象調用wait方法
  • 2.爲什麼wait方法和notify方法定義在Object這類中?

          因爲鎖對象可以是任意對象,Object是所有的類的基類,所以wait方法和notify方法需要定義在Object這個類中

  • 3.sleep方法和wait方法的區別?

          sleep方法必須傳入參數,參數就是時間,時間到了自動醒來

          wait方法可以傳入參數也可以不傳入參數,傳入參數就是在參數的時間結束後等待,不傳入參數就是直接等待

          sleep方法在同步函數或同步代碼塊中,不釋放鎖,睡着了也抱着鎖睡

          wait方法在同步函數或者同步代碼塊中,釋放鎖

三、JDK1.5的新特性互斥鎖

1.同步

使用ReentrantLock類的lock()和unlock()方法進行同步

2.通信

使用ReentrantLock類的newCondition()方法可以獲取Condition對象

需要等待的時候使用Condition的await()方法,喚醒的時候用signal()方法

不同的線程使用不同的Condition,這樣就能區分喚醒的時候找哪個線程了

3.代碼

class Printer3 {
	private ReentrantLock r = new ReentrantLock();
	private Condition c1 = r.newCondition();
	private Condition c2 = r.newCondition();
	private Condition c3 = r.newCondition();
	
	private int flag = 1;
	public void print1() throws InterruptedException {
		r.lock();								//獲取鎖
			if(flag != 1) {
				c1.await();
			}
			System.out.print("黑");
			System.out.print("馬");
			System.out.print("程");
			System.out.print("序");
			System.out.print("員");
			System.out.print("\r\n");
			flag = 2;
			c2.signal();
		r.unlock();								//釋放鎖
	}
	
	public void print2() throws InterruptedException {
		r.lock();
			if(flag != 2) {
				c2.await();
			}
			System.out.print("傳");
			System.out.print("智");
			System.out.print("播");
			System.out.print("客");
			System.out.print("\r\n");
			flag = 3;
			c3.signal();
		r.unlock();
	}
	
	public void print3() throws InterruptedException {
		r.lock();
			if(flag != 3) {
				c3.await();
			}
			System.out.print("i");
			System.out.print("t");
			System.out.print("h");
			System.out.print("e");
			System.out.print("i");
			System.out.print("m");
			System.out.print("a");
			System.out.print("\r\n");
			flag = 1;
			c1.signal();
		r.unlock();
	}
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章