1. 程式人生 > >java多執行緒輪流列印資料問題

java多執行緒輪流列印資料問題

  題目是:

建立三個執行緒,A執行緒列印10次A,B執行緒列印10次B,C執行緒列印10次C,要求執行緒同時執行,交替列印10次ABC

理解:

       Obj.wait(),與Obj.notify()必須要與synchronized(Obj)一起使用,也就是wait,與notify是針對已經獲取了Obj鎖進行操作,從語法角度來說就是Obj.wait(),Obj.notify必須在synchronized(Obj){...}語句塊內。從功能上來說wait就是說執行緒在獲取物件鎖後,主動釋放物件鎖,同時本執行緒休眠。直到有其它執行緒呼叫物件的notify()喚醒該執行緒,才能繼續獲取物件鎖,並繼續執行。相應的notify()就是對物件鎖的喚醒操作。但有一點需要注意的是notify()呼叫後,並不是馬上就釋放物件鎖的,而是在相應的synchronized(){}語句塊執行結束,自動釋放鎖後,JVM會在wait()物件鎖的執行緒中隨機選取一執行緒,賦予其物件鎖,喚醒執行緒,繼續執行。這樣就提供了線上程間同步、喚醒的操作。Thread.sleep()與Object.wait()二者都可以暫停當前執行緒,釋放CPU控制權,主要的區別在於Object.wait()在釋放CPU同時,釋放了物件鎖的控制。

程式碼實現是:

public class PrintRunnable implements Runnable {

	private int count = 10;
	private String name;
	private Object pre;
	private Object own;
	public PrintRunnable(String name,Object pre,Object own) {
		this.name = name;
		this.pre = pre;
		this.own = own;
	}
	@Override
	public void run() {
		while(count > 0){
			synchronized (pre) {
				synchronized (own) {
					System.out.print(name);
					count--;
					own.notify();
				}
				try {
					pre.wait();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}
}

測試程式碼是:
public class MainTest {

	public static void main(String[] args) throws InterruptedException {
		
		Object a = new Object();
		Object b = new Object();
		Object c = new Object();
		Thread t1 = new Thread(new PrintRunnable("A", c, a));
		Thread t2 = new Thread(new PrintRunnable("B", a, b));
		Thread t3 = new Thread(new PrintRunnable("C", b, c));
		t1.start();
		Thread.sleep(100);
		t2.start();
		Thread.sleep(100);
		t3.start();
		Thread.sleep(100);
	}
}

測試結果:

ABCABCABCABCABCABCABCABCABCABC

分析:

首先啟動第一個執行緒,列印一個A,喚醒A鎖,count--,(c.wait():釋放C鎖,第一個執行緒在迴圈中等待)。

其次啟動第二個執行緒,列印一個B,喚醒B鎖,count--,(a.wait():釋放A鎖,第二個執行緒在迴圈中等待)。

最後啟動第三個執行緒,列印一個C,喚醒C鎖,count--,(b.wait():釋放B鎖,第三個執行緒在迴圈中等待)。

由於第三個執行緒在迴圈中喚醒C鎖,其執行完之後,會喚醒持有C鎖等待的第一個執行緒,然後第一個執行緒執行完之後再喚醒迴圈中持有B鎖的第二個執行緒,同理,依次執行喚醒操作。