java多線程通信
最近在研究java多線程,這篇文章主要是介紹一些線程之間的通信:
1:join 的方式,一個線程等待另一個線程執行完畢後在執行,可以控制線程執行的順序;
場景:B線程要在A線程完成後才開始任務:
不做任何控制的情況下的線程代碼如下:
@Test public void threadTest4() throws InterruptedException, ExecutionException { // 線程A final Thread threadA = new Thread(new Runnable() { @Overridepublic void run() { printNum("線程A"); } }); // 線程B Thread threadB= new Thread(new Runnable() { @Override public void run() { // try { // threadA.join(); // } catch (InterruptedException e) {// e.printStackTrace(); // } printNum("線程B"); } }); threadA.start(); threadB.start(); Thread.sleep(1000); }
private void printNum(String threadName){ int i=0; while (i++<3){ try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(threadName+"打印"+i); } }
這樣打印出來的效果如下:
線程B打印1 線程A打印1 線程B打印2 線程A打印2 線程B打印3 線程A打印3
這樣不能保證 B 線程在A 線程執行完之後再執行;可以通過 join 方法來實現我們的需求: 當在 B 線程調用 A線程的join 方法 則會 B 線程等待A線程執行完了之後再執行B 線程;將上面註掉的代碼解開就行了;
這樣打印出來的效果是:
線程A打印1 線程A打印2 線程A打印3 線程B打印1 線程B打印2 線程B打印3
這樣就能保證 B 線程在 A線程執行結束後再執行;
2:多個線程按照一定的順序交叉執行:
場景:A 線程執行打印完 1 2 後 B 線程再執行打印 1 2 3
這樣的場景需要使用 鎖的等待和喚醒的機制來實現,代碼實現如下: 需要用到兩個方法 wait 和 notify 方法 這兩個方法都是 Object對象的方法;
@Test public void threadTest5() throws InterruptedException, ExecutionException { final Object o=new Object(); Thread threadA = new Thread(new Runnable() { @Override public void run() { synchronized (o){ System.out.println("線程A 打印 1"); try { o.wait(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("線程A 打印 2"); System.out.println("線程A 打印 3"); } } }); Thread threadB = new Thread(new Runnable() { @Override public void run() { synchronized (o){ System.out.println("線程B 打印 1"); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("線程B 打印 2"); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("線程B 打印 3"); o.notify(); } } }); threadA.start(); threadB.start(); Thread.sleep(1000); }
下面分析這段代碼的執行順序:
1:創建對象鎖
final Object o=new Object();
2:A 首先獲得對象鎖的控制權;
3:A 調用 wait 方法 讓出對象鎖的控制權:
o.wait();
4:B 線程獲得對象鎖的控制權:
B線程的業務代碼處理完之後 調用 notify 方法,喚醒 正在 wait 的線程 然後結束B線程的同步代碼塊,
5:A 線程獲取到了對象鎖的控制權後執行自己的業務邏輯;
這樣就滿足我們需要的場景;
3: 四個線程 A B C D,其中 D 要等到 A B C 全執行完畢後才執行,而且 A B C 是同步運行的
通過 調用對象鎖的 notify 和 wait 方法可以滿足線程的執行順序 但是線程是一次執行的,不能同時進行;
需要同步進行有需要進行控制線程的執行順序則可以使用 線程計數器來實現
代碼如下:
@Test public void threadTest1() throws InterruptedException { int worker = 3; System.out.println("計數器的值為:" + worker); final CountDownLatch countDownLatch = new CountDownLatch(worker); Thread threadD = new Thread(new Runnable() { @Override public void run() { System.out.println("D 線程等待其他線程!"); try { countDownLatch.await(); System.out.println("其他線程運行結束,D線程開始"); } catch (InterruptedException e) { e.printStackTrace(); } } }); threadD.start(); for (int i = 0; i < 3; i++) { final int finalI = i; Thread threadA = new Thread(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + finalI + "is working"); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + finalI + "is finish"); countDownLatch.countDown(); } }); threadA.start(); } Thread.sleep(1000); }
上面代碼的執行順序如下:
1:創建線程計數器:計數器的計數個數為3;
2:當D線程開始執行的時候調用計數器的 await 方法,然後等待;
3:執行 ABC 線程的業務邏輯的處理,在線程的業務邏輯處理之後分別調用 計數器的 數字減1.
4:當計數器的數值為0 時D線程獲得執行權,開始執行;
4:多線程獲取線程處理的返回值:
代碼如下:
@Test public void threadTest3() throws InterruptedException, ExecutionException { Callable<Integer> callable = new Callable<Integer>() { @Override public Integer call() throws Exception { System.out.println("開始任務!!"); Thread.sleep(100); int result=0; for (int i = 0; i <100 ; i++) { result +=i; } return result; } }; FutureTask<Integer> futureTask = new FutureTask<Integer>(callable); new Thread(futureTask).start(); System.out.println("任務獲取前"); System.out.println("任務獲取到的結果是:"+futureTask.get()); System.out.println("任務獲取後"); Thread.sleep(1000); }
通過Callable 和 FutureTask 兩類可以實現這個功能, 註意 FutureTask 的 get()方法是同步,必須在callable中的call 方法執行結束後;
java多線程通信