java實現執行緒間的通訊
本文章旨在記錄java執行緒之間通訊的使用方法(學習為主),文中涉及的程式碼非原創。
如何讓兩個執行緒同時執行?
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使用於一個執行緒等待多個執行緒的場景。
============================================
學習結束,以後繼續學習執行緒相關知識。