java 阻塞等待子線程結束的幾種方式

導語

java主線程等待一個或多個子線程結束具有十分廣泛的應用,比如在合併計算結果或方法中都具有非常重要的意義,那麼我們今天就來總結一下,到底有多少種方法能夠實現。

java 阻塞等待子線程結束的幾種方式

這就是最全,沒有更全

1.join方式

join方式非常的簡單易懂,但是實現起來代碼結構糟糕,不推薦使用


join
public final void join() throws InterruptedException Waits for this thread to die. Throws: InterruptedException - if any thread has interrupted the current thread. The interrupted status of the current thread is cleared when this exception is thrown.

實現方式

class BThread extends Thread {
public BThread() {
super("[BThread] Thread");
};
public void run() {
String threadName = Thread.currentThread().getName();
System.out.println(threadName + " start.");
try {
for (int i = 0; i < 5; i++) {
System.out.println(threadName + " loop at " + i);
Thread.sleep(1000);
}
System.out.println(threadName + " end.");
} catch (Exception e) {
System.out.println("Exception from " + threadName + ".run");
}
}
}
class AThread extends Thread {
BThread bt;
public AThread(BThread bt) {
super("[AThread] Thread");
this.bt = bt;

}
public void run() {
String threadName = Thread.currentThread().getName();
System.out.println(threadName + " start.");
try {
bt.join();
System.out.println(threadName + " end.");
} catch (Exception e) {
System.out.println("Exception from " + threadName + ".run");
}
}
}
public class TestDemo {
public static void main(String[] args) {
String threadName = Thread.currentThread().getName();
System.out.println(threadName + " start.");
BThread bt = new BThread();
AThread at = new AThread(bt);
try {
bt.start();
Thread.sleep(2000);
at.start();
at.join();
} catch (Exception e) {
System.out.println("Exception from main");
}
System.out.println(threadName + " end!");
}
}


2.wait同步

使用wait/notifyAll,這個方式其實跟上面是類似的,只是比較底層些吧(join實際上也是wait)。

實現方式

@Test 
2 public void testThreadSync2() throws IOException, InterruptedException {
3 final Object waitObject = new Object();
4 final AtomicInteger count = new AtomicInteger(TEST_THREAD_COUNT);
5 final Vector<integer> list = new Vector<integer>();

6 Thread[] threads = new Thread[TEST_THREAD_COUNT];
7 for (int i = 0; i < TEST_THREAD_COUNT; i++) {
8 final int num = i;
9 threads[i] = new Thread(new Runnable() {
10 public void run() {
11 try {
12 Thread.sleep(random.nextInt(100));
13 } catch (InterruptedException e) {
14 e.printStackTrace();
15 }
16 list.add(num);
17 System.out.print(num + " add.\t");
18 synchronized (waitObject) {
19 int cnt = count.decrementAndGet();
20 if (cnt == 0) {
21 waitObject.notifyAll();
22 }
23 }
24 }
25 });
26 threads[i].start();
27 }
28 synchronized (waitObject) {
29 while (count.get() != 0) {
30 waitObject.wait();
31 }
32 }
33 printSortedResult(list);
34 }
/<integer>/<integer>

3.Future

 Future是一個任務執行的結果, 他是一個將來時, 即一個任務執行, 立即異步返回一個Future對象, 等到任務結束的時候, 會把值返回給這個future對象裡面. 我們可以使用ExecutorService接口來提交一個線程.(注意:Future.get()為一個阻塞方法)。

java 阻塞等待子線程結束的幾種方式

實現方式

public class FutureDemo {
//創建一個容量為1的線程池
static ExecutorService executorService = Executors.newFixedThreadPool(1);

public static void main(String[] args) throws Exception {
//創建線程並提交線程,同時獲取一個future對象
Thread subThread = new Thread(new SubThread());
Future future = executorService.submit(subThread);
//主線程處理其他工作,讓子線程異步去執行
mainWork();
//阻塞,等待子線程結束
future.get();
System.out.println("Now all thread done!");
//關閉線程池
executorService.shutdown();
}
//主線程工作
private static void mainWork(){
System.out.println("Main thread start work!");
try {
Thread.sleep(2000L);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Main Thread work done!");
}
/**
* 子線程類
* @author fuhg
*/
private static class SubThread implements Runnable{
public void run() {
// TODO Auto-generated method stub
System.out.println("Sub thread is starting!");
try {
Thread.sleep(5000L);
} catch (InterruptedException e) {
// TODO Auto-generated catch block

e.printStackTrace();
}
System.out.println("Sub thread is stopping!");
}
}
}

4.CountDownLatch

使用CountDownLatch,這其實是最優雅的寫法了,每個線程完成後都去將計數器減一,最後完成時再來喚醒。

@Test 
2 public void testThreadSync3() {
3 final Vector<integer> list = new Vector<integer>();
4 Thread[] threads = new Thread[TEST_THREAD_COUNT];
5 final CountDownLatch latch = new CountDownLatch(TEST_THREAD_COUNT);
6 for (int i = 0; i < TEST_THREAD_COUNT; i++) {
7 final int num = i;
8 threads[i] = new Thread(new Runnable() {
9 public void run() {
10 try {
11 Thread.sleep(random.nextInt(100));
12 } catch (InterruptedException e) {
13 e.printStackTrace();
14 }
15 list.add(num);
16 System.out.print(num + " add.\t");
17 latch.countDown();
18 }
19 });
20 threads[i].start();
21 }
22 try {
23 latch.await();
24 } catch (InterruptedException e) {
25 e.printStackTrace();
26 }
27 printSortedResult(list);
28 }
/<integer>/<integer>

5.CyclicBarrier

其實這個主要功能不是控制線程是否結束的,而是設置如同柵欄一樣的起始點,用在這裡是大材小用。

@Test 
2 public void testThreadSync4() throws IOException {
3 final Vector<integer> list = new Vector<integer>();
4 Thread[] threads = new Thread[TEST_THREAD_COUNT];
5 final CyclicBarrier barrier = new CyclicBarrier(TEST_THREAD_COUNT,
6 new Runnable() {
7 public void run() {
8 printSortedResult(list);
9 }
10 });
11 for (int i = 0; i < TEST_THREAD_COUNT; i++) {
12 final int num = i;
13 threads[i] = new Thread(new Runnable() {
14 public void run() {
15 try {
16 Thread.sleep(random.nextInt(100));
17 } catch (InterruptedException e) {
18 e.printStackTrace();
19 }
20 list.add(num);
21 System.out.print(num + " add.\t");
22 try {
23 barrier.await();
24 } catch (InterruptedException e) {
25 e.printStackTrace();
26 } catch (BrokenBarrierException e) {
27 e.printStackTrace();
28 }
29 }
30 });
31 threads[i].start();
32 }
33 System.in.read();
34 }
/<integer>/<integer>

6.ThreadPoolExecuter線程池

用java線程池,比如 ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5);

在線程調度後面加上下面代碼:


fixedThreadPool.shutdown();
while (true) {//等待所有任務都執行結束
if (fixedThreadPool.isTerminated()) {//所有的子線程都結束了

System.out.println("共耗時:"+(System.currentTimeMillis()-startTime)/1000.0+"s");
break;
}
}


分享到:


相關文章: