一、前言
关于java场景多线程应用场景中,主任务线程任务结束完成依赖所有子任务线程都执行完成后,主任务才算完成最终任务,下面根据不同应用方式整理具体代码示例进行说明。
二、代码示例
1) 方法1:通过线程池executors.isTerminated()进行等待子任务线程完成
package thread.wait;@b@@b@import java.util.concurrent.ExecutorService;@b@import java.util.concurrent.Executors;@b@@b@public class MainThreadWaitTest1 {@b@ @b@ private static ExecutorService executors;@b@ @b@ public static void main(String[] args) throws Exception{@b@ //main job开始i@b@ System.out.println(Thread.currentThread().getName()+" run begin............");@b@ @b@ executors = Executors.newScheduledThreadPool(3);@b@ for(int i=0;i<10;i++){@b@ executors.submit(new Runnable() {@b@ @Override@b@ public@b@ void run() {@b@ //子线程开始工作@b@ System.out.println(Thread.currentThread().getName()+" working......");@b@ try {@b@ Thread.sleep(50);@b@ } catch (InterruptedException e) {@b@ }@b@ //子线程完成工作@b@ System.out.println(Thread.currentThread().getName()+" work finished......");@b@ }@b@ }); @b@ }@b@ @b@ executors.shutdown();@b@ //等待@b@ while (!executors.isTerminated()) {@b@ System.out.println(Thread.currentThread().getName()+"等待子线程完成任务,waiting...");@b@ Thread.currentThread().sleep(500);@b@ }@b@ @b@ //等待所有子任务线程工作完成后,总的main线程算完成任务@b@ System.out.println(Thread.currentThread().getName()+" all jobs finished ***************");@b@ }@b@@b@}
控制台打印结果如下
main run begin............@b@pool-1-thread-2 working......@b@main等待子线程完成任务,waiting...@b@pool-1-thread-1 working......@b@pool-1-thread-3 working......@b@pool-1-thread-3 work finished......@b@pool-1-thread-1 work finished......@b@pool-1-thread-2 work finished......@b@pool-1-thread-1 working......@b@pool-1-thread-2 working......@b@pool-1-thread-3 working......@b@pool-1-thread-3 work finished......@b@pool-1-thread-2 work finished......@b@pool-1-thread-1 work finished......@b@pool-1-thread-2 working......@b@pool-1-thread-3 working......@b@pool-1-thread-1 working......@b@pool-1-thread-2 work finished......@b@pool-1-thread-2 working......@b@pool-1-thread-1 work finished......@b@pool-1-thread-3 work finished......@b@pool-1-thread-2 work finished......@b@main all jobs finished ***************
2) 方法2:Semaphore信号量方式 - 通过 acquire() 获取一个许可,如果没有就等待,而 release() 释放一个许可。
package thread.wait;@b@@b@import java.util.concurrent.ExecutorService;@b@import java.util.concurrent.Executors;@b@import java.util.concurrent.Semaphore;@b@@b@public class MainThreadWaitTest2 {@b@ @b@ private static Semaphore semaphore=new Semaphore(3);@b@ @b@ private static ExecutorService executors;@b@ @b@ public static void main(String[] args) throws Exception{@b@ //main job开始i@b@ System.out.println(Thread.currentThread().getName()+" run begin............");@b@ @b@ executors = Executors.newScheduledThreadPool(3);@b@ for(int i=0;i<10;i++){@b@ executors.submit(new Runnable() {@b@ @Override@b@ public void run() {@b@ try {@b@ semaphore.acquire();@b@ //子线程开始工作@b@ System.out.println(Thread.currentThread().getName()+" working......");@b@ Thread.sleep(50);@b@ } catch (Exception e) {@b@ e.printStackTrace();@b@ }@b@ semaphore.release();@b@ //子线程完成工作@b@ System.out.println(Thread.currentThread().getName()+" work finished......");@b@ }@b@ }); @b@ Thread.sleep(50);@b@ }@b@ @b@ //等待所有子任务线程工作完成后,总的main线程算完成任务@b@ semaphore.acquireUninterruptibly();@b@// semaphore.acquire(3);@b@ System.out.println(Thread.currentThread().getName()+" all jobs finished ***************");@b@ }@b@@b@}
控制台打印结果如下
main run begin............@b@pool-1-thread-1 working......@b@pool-1-thread-1 work finished......@b@pool-1-thread-1 working......@b@pool-1-thread-1 work finished......@b@pool-1-thread-1 working......@b@pool-1-thread-1 work finished......@b@pool-1-thread-2 working......@b@pool-1-thread-2 work finished......@b@pool-1-thread-3 working......@b@pool-1-thread-3 work finished......@b@pool-1-thread-1 working......@b@pool-1-thread-1 work finished......@b@pool-1-thread-2 working......@b@pool-1-thread-2 work finished......@b@pool-1-thread-3 working......@b@pool-1-thread-3 work finished......@b@pool-1-thread-1 working......@b@pool-1-thread-1 work finished......@b@pool-1-thread-2 working......@b@pool-1-thread-2 work finished......@b@main all jobs finished ***************
3) 方法3:CountDownLatch方式 - 是通过一个计数器来实现的,计数器的初始值是线程的数量。每当一个线程执行完毕后,计数器的值就-1,当计数器的值为0时,表示所有线程都执行完毕。
package thread.wait;@b@@b@import java.util.concurrent.CountDownLatch;@b@import java.util.concurrent.ExecutorService;@b@import java.util.concurrent.Executors;@b@@b@public class MainThreadWaitTest3 {@b@ @b@ private static final CountDownLatch countDownLatch = new CountDownLatch(10);@b@ @b@ private static ExecutorService executors;@b@ @b@ public static void main(String[] args) throws Exception{@b@ //main job开始i@b@ System.out.println(Thread.currentThread().getName()+" run begin............");@b@ @b@ executors = Executors.newScheduledThreadPool(3);@b@ for(int i=0;i<10;i++){@b@ executors.submit(new Runnable() {@b@ @Override@b@ public@b@ void run() {@b@ try {@b@ //子线程开始工作@b@ System.out.println(Thread.currentThread().getName()+" working......");@b@// Thread.sleep(50);@b@ } catch (Exception e) {@b@ } finally {@b@ countDownLatch.countDown(); //这个不管是否异常都需要数量减,否则会被堵塞无法结束@b@ }@b@@b@ //子线程完成工作@b@ System.out.println(Thread.currentThread().getName()+" work finished......");@b@ }@b@ }); @b@ Thread.sleep(50);@b@ }@b@ @b@ //等待所有子任务线程工作完成后,总的main线程算完成任务@b@ countDownLatch.await();@b@ System.out.println(Thread.currentThread().getName()+" all jobs finished ***************");@b@ }@b@@b@}
控制台打印结果如下
main run begin............@b@pool-1-thread-1 working......@b@pool-1-thread-1 work finished......@b@pool-1-thread-1 working......@b@pool-1-thread-1 work finished......@b@pool-1-thread-1 working......@b@pool-1-thread-1 work finished......@b@pool-1-thread-2 working......@b@pool-1-thread-2 work finished......@b@pool-1-thread-1 working......@b@pool-1-thread-1 work finished......@b@pool-1-thread-3 working......@b@pool-1-thread-3 work finished......@b@pool-1-thread-2 working......@b@pool-1-thread-2 work finished......@b@pool-1-thread-1 working......@b@pool-1-thread-1 work finished......@b@pool-1-thread-3 working......@b@pool-1-thread-3 work finished......@b@pool-1-thread-2 working......@b@pool-1-thread-2 work finished......@b@main all jobs finished ***************
4) 方法四 - CompletableFuture的allOf..join
package com.xwood.demo.threads;@b@@b@import java.util.concurrent.CompletableFuture;@b@import java.util.function.Consumer;@b@@b@public class CompletableFutureTest {@b@@b@@b@ public static void main(String[] args) throws Exception{@b@ //cf1子线程@b@ CompletableFuture cf1= CompletableFuture.runAsync(new Runnable() {@b@ @Override@b@ public void run() {@b@ System.out.println(Thread.currentThread().getName()+"@cf1 execute begin...");@b@ try {@b@ Thread.sleep(1000);@b@ } catch (InterruptedException e) {}@b@ System.out.println(Thread.currentThread().getName()+"@cf1 execute finished...");@b@ }@b@ });@b@ //cf2子线程@b@ CompletableFuture cf2= CompletableFuture.runAsync(new Runnable() {@b@ @Override@b@ public void run() {@b@ System.out.println(Thread.currentThread().getName()+"@cf2 execute begin...");@b@ try {@b@ Thread.sleep(1000);@b@ } catch (InterruptedException e) {}@b@ System.out.println(Thread.currentThread().getName()+"@cf2 execute finished...");@b@ }@b@ });@b@@b@ //等待所有cf1、cf2子线程执行后@b@ CompletableFuture.allOf(cf1,cf2).thenAccept(new Consumer<Void>() {@b@ @Override@b@ public void accept(Void aVoid) {@b@ System.out.println(Thread.currentThread().getName()+"@all execute begin...");@b@ try {@b@ Thread.sleep(1000);@b@ } catch (InterruptedException e) {}@b@ System.out.println(Thread.currentThread().getName()+"@all execute finished...");@b@ }@b@ }).join();@b@ //简单等待处理@b@ //CompletableFuture.allOf(cf1,cf2).join();@b@@b@ //主main线程@b@ System.out.println(Thread.currentThread().getName()+"@main thread execute finished...");@b@@b@ }@b@@b@@b@}
控制台执行打印结果
ForkJoinPool.commonPool-worker-1@cf1 execute begin...@b@ForkJoinPool.commonPool-worker-2@cf2 execute begin...@b@ForkJoinPool.commonPool-worker-1@cf1 execute finished...@b@ForkJoinPool.commonPool-worker-2@cf2 execute finished...@b@ForkJoinPool.commonPool-worker-2@all execute begin...@b@ForkJoinPool.commonPool-worker-2@all execute finished...@b@main@main thread execute finished...
5)方法五 - future.get() 等待所有子任务执行完成,具体代码示例