使用Thread的join方法packagecom.qcy.testThreadFinish;/***@authorqcy*@create2020/09/0917:05:23*/publicclassCase1{publicstaticvoidmain(String[]args)throwsInterruptedException{Threadt1=newThread(()->{try{Thread.sleep(3000);}catch(InterruptedExceptione){e.printStackTrace();}});t1.start();Threadt2=newThread(()->{try{Thread.sleep(3000);}catch(InterruptedExceptione){e.printStackTrace();}});t2.start();t1.join();t2.join();System.out.println("结束mainthread");}}join()方法让主线程等待子线程执行完毕,主线程被阻塞。其底层原理可以参考我的文章你真的了解Thread.join吗?使用线程池的isTerminated方法packagecom.qcy.testThreadFinish;importjava.util.concurrent.ExecutorService;importjava.util.concurrent.Executors;/***@authorqcy*@create2020/09/0917:05:23*/publicclassCase2{publicstaticvoidmain(String[]args){ExecutorServicepool=Executors.newFixedThreadPool(3);pool.execute(()->{try{Thread.sleep(2000);}catch(InterruptedExceptione){e.printStackTrace();}});pool.execute(()->{try{Thread.sleep(2000);}catch(InterruptedExceptione){e.printStackTrace();}});//不再接受新任务pool.shutdown();while(true){//手动循环确实效率低下,不推荐println("主线程结束");}}isTerminated,当shutdown()方法被调用,所有提交的任务都完成后,会返回true,这里直接使用固定大小的线程池。线程池的参数在面试中经常被问到。对线程池不熟悉的同学可以参考我这篇关于Future机制的使用的文章;进口未来task1=pool.submit(()->{try{Thread.sleep(2000);}catch(InterruptedExceptione){e.printStackTrace();}return2;});Futuretask2=pool。submit(()->{try{Thread.sleep(2000);}catch(InterruptedExceptione){e.printStackTrace();}return3;});//没有新任务pool.shutdown();//get方法正在阻塞获取System.out.println("task1的运行结果:"+task1.get());System.out.println("task2的运行结果:"+task2.get());系统输出。println("主线程结束");}}Future机制,可以参考我的另一篇博客讲Future、Callable、FutureTask的关系usingCountDownLatchpackagecom.qcy.testThreadFinish;importjava.util.concurrent.CountDownLatch;/***@authorqcy*@create2020/09/0917:05:23*/publicclassCase5{publicstaticvoidmain(String[]args)throwsInterruptedException{CountDownLatchlatch=newCountDownLatchlatch=newCountDownLatchlatchuntDownLatch(2);Threadt1=newThread(()->{try{Thread.sleep(3000);}catch(InterruptedExceptione){e.printStackTrace();}finally{latch.countDown();}});t1。start();Threadt2=newThread(()->{try{Thread.sleep(3000);}catch(InterruptedExceptione){e.printStackTrace();}finally{latch.countDown();}});t2.start();latch.await();System.out.println("主线程结束");}}每调用一次countDown方法,计数器就会减1,在计数器减到0之前,await方法会阻塞主线程CountDownLatch的底层原理可以参考我的另一篇博客CountDownLatch实现原理usingCompletableFuturepackagecom.qcy.testThreadFinish;importjava.util.concurrent.CompletableFuture;importjava.util.concurrent.ExecutionException;/***@authorqcy*@create2020/09/0917:05:23*/publicclassCase6{publicstaticvoidmain(String[]args)throwsInterruptedException,ExecutionException{CompletableFuturecf1=CompletableFuture.supplyAsync(()->{try{Thread.sleep(3000);}catch(InterruptedExceptione){e.printStackTrace();}return2;});CompletableFuturecf=CompletableFuture.supplyAsync(()->{try{Thread.sleep(3000);}catch(InterruptedExceptione){e.printStackTrace();}return3;}).thenCombine(cf1,(result1,result2)->result1*result2);//get方法阻塞获取System.out.println("计算结果为"+cf.get());系统。out.println("主线程结束");}}等到两个子任务完成,输出两个数的乘积,然后执行主线程。对CompletableFuture不熟悉的同学可以参考我的文章么,你还不知道CompletableFuture怎么用?