1. 程式人生 > >java實現執行緒間的通訊

java實現執行緒間的通訊

本文章旨在記錄java執行緒之間通訊的使用方法(學習為主),文中涉及的程式碼非原創。

來源:http://wingjay.com

如何讓兩個執行緒同時執行?

public class threadTest {

	public static void main(String[] args) {
		Thread A = new Thread(new Runnable() {

			@Override
			public void run() {
				printNumber("A");
			}
		});
		
		Thread B = new Thread(new Runnable() {
			
			@Override
			public void run() {
				printNumber("B");
			}
		});
		A.start();
		B.start();
	}

	public static void printNumber(String s) {
		int i = 0;
		while (i++ < 3) {
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println(s + "===print:" + i);
		}
	}
}

多次輸出結果(觀察下面幾張圖的不同點與相同點):

             

我們可以看出,A、B執行緒是同時執行的。

如何等待一個執行緒執行完畢再執行另外一個?

public class threadTest {

	public static void main(String[] args) {
		Thread A = new Thread(new Runnable() {

			@Override
			public void run() {
				printNumber("A");
			}
		});
		
		Thread B = new Thread(new Runnable() {
			@Override
			public void run() {
				System.out.println("B開始等待A執行緒");
				try {
					A.join();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				printNumber("B");
			}
		});
		A.start();
		B.start();
	}

	public static void printNumber(String s) {
		int i = 0;
		while (i++ < 3) {
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println(s + "===print:" + i);
		}
	}
}

輸出結果:

觀察結果,可以看到在B執行緒中先輸出了一句“B開始等待A執行緒”,然後A執行緒開始執行,A執行緒執行完畢最後B執行緒開始執行,之所以會這樣,因為我們加了這句程式碼,A.join();

join()方法的作用是使當前的執行緒停止下來,等待呼叫的執行緒執行完畢後再執行自身執行緒。(使得執行緒之間的並行操作暫時改變為序列操作)

如何讓兩個執行緒按照指定順序交叉執行?

如果想要按照自己定義的順序執行執行緒,依賴於join()是不行的,得需要更細粒度的去控制執行緒的執行順序。

public class threadTest {

	public static void main(String[] args) {
		Object lock = new Object();
		Thread A = new Thread(new Runnable() {
			
			@Override
			public void run() {
				synchronized (lock) {
					System.out.println("A1");
					try {
						lock.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println("A2");
					System.out.println("A3");
				}
				
			}
		});
		
		Thread B = new Thread(new Runnable() {
			
			@Override
			public void run() {
				synchronized(lock) {
					System.out.println("B1");
					System.out.println("B2");
					System.out.println("B3");
					lock.notify();
				}
			}
		});
		
		A.start();
		B.start();
	}
}

輸出結果:

解釋下輸出結果:

首先兩個執行緒A、B共用一個物件鎖,當A執行緒開始執行時將物件鎖取走,此時B執行緒處於等待狀態;A執行緒輸出A1後呼叫方法wait(),使自身執行緒進入等待狀態,釋放對物件鎖的持有權,此時B執行緒獲得物件鎖開始執行執行緒,分別輸出B1、B2、B3,輸出完畢後B執行緒呼叫notify()方法喚醒處於等待狀態的A執行緒,A執行緒繼續執行輸出A2、A3。

如何使一個執行緒等待多個執行緒?

前面用到的join()方法可以使得當前執行緒等待其他執行緒,那如果需要等待多個執行緒該怎麼辦呢,我們可以用CountDownLatch。

public class threadTest {

	public static void main(String[] args) {
		int count = 3;
		CountDownLatch countDownLatch = new CountDownLatch(count);
		new Thread(new Runnable() {
			
			@Override
			public void run() {
				System.out.println("當前執行緒為D執行緒,等待其他3個執行緒。");
				try {
					countDownLatch.await();
					System.out.println("其他3個執行緒已執行完畢,D執行緒開始...");
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}).start();
		
		for(char threadName='A';threadName <='C';threadName++) {
			String name= String.valueOf(threadName);
			new Thread(new Runnable() {
				
				@Override
				public void run() {
					System.out.println(name + "執行緒開始執行");
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println(name + "執行緒執行完畢");
					countDownLatch.countDown();
				}
			}).start();
		}
	}
}

CountDownLatch相當於一個計數器,首先需要給他初始化一個計數值,當其他執行緒執行時我們可以遞減這個計數值,當這個計數值減到0時,當前執行緒就可以繼續執行了。

countDownLatch.await()   檢查計數值是否為0,不為0時繼續等待,為0時開始執行。

countDownLatch.countDown()    逐漸計數值,每次減。

CountDownLatch使用於一個執行緒等待多個執行緒的場景。

============================================

學習結束,以後繼續學習執行緒相關知識。