最近在研究java多線程,這篇文章主要是介紹一些線程之間的通訊:java
1:join 的方式,一個線程等待另外一個線程執行完畢後在執行,能夠控制線程執行的順序;多線程
場景:B線程要在A線程完成後纔開始任務:ide
不作任何控制的狀況下的線程代碼以下:spa
@Test public void threadTest4() throws InterruptedException, ExecutionException { // 線程A final Thread threadA = new Thread(new Runnable() { @Override public 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 線程;將上面注掉的代碼解開就好了;code
這樣打印出來的效果是:對象
線程A打印1 線程A打印2 線程A打印3 線程B打印1 線程B打印2 線程B打印3
這樣就能保證 B 線程在 A線程執行結束後再執行;blog
2:多個線程按照必定的順序交叉執行:get
場景: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 方法執行結束後;