线程池如何保证所有子线程运行完再执行主线程

转:https://blog.csdn.net/M983373615/article/details/97116131

java主线程等待所有子线程执行完毕在执行,其实在我们的工作中经常的用到,比如说主线程要返回一个响应用户的值,但这个值得赋值过程是由过个子线程来完成的(模拟一个实际开发的情景),所以主线程必须等待子线程执行完毕,再响应用户;否则,响应用户的是一个无意义的值。

那么如何确保所有的子线程执行完毕了。一般的有如下方法:

使用 ExecutorService线程池,等待所有任务执行完毕再执行主线程,awaitTermination。
我的解决办法如下:
awaitTermination(long timeout,TimeUnit unit)
请求关闭、发生超时或者当前线程中断,无论哪一个首先发生之后,都将导致阻塞,直到所有任务完成执行。
解决方案:

import java.util.concurrent.CountDownLatch;

public class MyThread extends Thread {
    public MyThread(CountDownLatch threadSignal){
        System.out.println("线程子启动,需要5秒....");
        for (int i = 0; i < 5; i++) {
            System.out.print(i + 1+",");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("线程创建完毕.....");
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.print("i = " + i+",");

        }
        System.out.println();
    }
}

 

import java.util.concurrent.*;

public class Demo {
    public static void main(String[] args) throws InterruptedException {

        // 初始化countDown
        CountDownLatch threadSignal = new CountDownLatch(5);
        // 使用线程池
        ExecutorService service = Executors.newScheduledThreadPool(5);
        MyThread myThread = new MyThread(threadSignal);

        for (int i=0;i<5;i++) {
            service.submit(myThread);
        }

        service.shutdown();
        // service.isTerminated()判断子线程是否全部完成;完成 :true;没完成 :falese
        System.out.println("调用awaitTermination之前:"+service.isTerminated());
        // 个人理解:如果service进行了shutdown操作,就查看子线程是否全部完成(也就是调用此方法),其中的参数相当于超时时间
        service.awaitTermination(1,TimeUnit.HOURS);
        System.out.println("调用awaitTermination之后:"+service.isTerminated());
        if (service.isTerminated()) {
            System.out.println("子线程执行完毕");
            System.out.println("主线程开始");
        }

    }
}

 

线程子启动,需要5秒....
1,2,3,4,5,线程创建完毕.....
睡两秒
i = 0,i = 1,i = 2,i = 3,i = 4,i = 5,i = 6,i = 7,i = 8,i = 9,i = 10,i = 11,i = 12,i = 13,i = 14,i = 15,i = 16,i = 17,i = 18,i = 19,i = 20,i = 21,i = 22,i = 23,i = 24,i = 25,i = 0,i = 26,i = 1,i = 27,i = 28,i = 0,i = 2,i = 0,i = 1,i = 2,i = 29,i = 30,i = 31,i = 32,i = 3,i = 3,i = 0,i = 1,i = 2,i = 3,i = 4,i = 5,i = 6,i = 7,i = 8,i = 9,i = 10,i = 11,i = 12,i = 13,i = 14,i = 15,i = 16,i = 17,i = 18,i = 19,i = 20,i = 1,i = 4,i = 5,i = 6,i = 7,i = 8,i = 9,i = 10,i = 11,i = 12,i = 13,i = 14,i = 15,i = 16,i = 17,i = 18,i = 19,i = 20,i = 4,i = 33,i = 5,i = 6,i = 7,i = 8,i = 9,i = 10,i = 11,i = 12,i = 13,i = 14,i = 15,i = 16,i = 17,i = 18,i = 19,i = 20,i = 21,i = 22,i = 23,i = 24,i = 25,i = 26,i = 21,i = 22,i = 23,i = 2,i = 21,i = 22,i = 3,i = 4,i = 5,i = 6,i = 24,i = 27,i = 25,i = 26,i = 34,i = 35,i = 36,i = 37,i = 38,i = 39,i = 40,i = 41,i = 42,i = 43,i = 44,i = 45,i = 46,i = 47,i = 48,i = 49,i = 50,i = 51,i = 52,i = 53,i = 54,i = 55,i = 56,i = 57,i = 58,i = 59,i = 60,i = 61,i = 62,i = 27,i = 28,i = 7,i = 8,i = 9,i = 10,i = 11,i = 12,i = 13,i = 23,i = 24,i = 25,i = 26,i = 27,i = 28,i = 29,i = 30,i = 31,i = 32,i = 33,i = 14,i = 15,i = 29,i = 28,i = 63,i = 29,i = 30,i = 31,i = 30,i = 16,i = 34,i = 17,i = 31,i = 32,i = 33,i = 34,i = 35,i = 36,i = 37,i = 38,i = 39,i = 40,i = 41,i = 42,i = 43,i = 44,i = 45,i = 46,i = 47,i = 64,i = 48,i = 32,i = 18,i = 35,i = 19,i = 33,i = 65,i = 49,i = 66,i = 34,i = 20,i = 36,i = 37,i = 38,i = 39,i = 40,i = 41,i = 21,i = 35,i = 36,i = 37,i = 38,i = 39,i = 40,i = 41,i = 42,i = 43,i = 44,i = 67,i = 50,i = 68,i = 45,i = 22,i = 42,i = 23,i = 46,i = 69,i = 70,i = 51,i = 71,i = 47,i = 24,i = 43,i = 25,i = 48,i = 72,i = 52,i = 73,i = 74,i = 75,i = 53,i = 49,i = 26,i = 44,i = 27,i = 50,i = 54,i = 76,i = 55,i = 51,i = 28,i = 45,i = 29,i = 52,i = 56,i = 77,i = 78,i = 57,i = 58,i = 59,i = 60,i = 53,i = 30,i = 31,i = 46,i = 47,i = 48,i = 49,i = 50,i = 51,i = 52,i = 53,i = 54,i = 55,i = 56,i = 57,i = 58,i = 59,i = 60,i = 61,i = 62,i = 63,i = 64,i = 65,i = 66,i = 67,i = 68,i = 69,i = 70,i = 71,i = 72,i = 73,i = 74,i = 75,i = 76,i = 77,i = 78,i = 32,i = 54,i = 61,i = 79,i = 62,i = 55,i = 33,i = 34,i = 35,i = 56,i = 57,i = 58,i = 79,i = 59,i = 36,i = 63,i = 80,i = 64,i = 37,i = 60,i = 80,i = 61,i = 38,i = 65,i = 81,i = 66,i = 39,i = 62,i = 81,i = 63,i = 40,i = 67,i = 82,i = 68,i = 69,i = 41,i = 64,i = 65,i = 82,i = 66,i = 42,i = 70,i = 83,i = 71,i = 43,i = 67,i = 83,i = 68,i = 44,i = 72,i = 84,i = 73,i = 45,i = 69,i = 84,i = 70,i = 46,i = 74,i = 85,i = 75,i = 47,i = 71,i = 85,i = 72,i = 48,i = 76,i = 86,i = 77,i = 49,i = 78,i = 73,i = 86,i = 74,i = 79,i = 50,i = 51,i = 87,i = 52,i = 80,i = 75,i = 87,i = 76,i = 81,i = 53,i = 88,i = 54,i = 82,i = 77,i = 88,i = 78,i = 83,i = 55,i = 89,i = 56,i = 84,i = 79,i = 85,i = 89,i = 86,i = 80,i = 81,i = 57,i = 90,i = 58,i = 82,i = 87,i = 90,i = 88,i = 83,i = 84,i = 59,i = 91,i = 60,i = 85,i = 89,i = 91,i = 90,i = 86,i = 61,i = 92,i = 62,i = 87,i = 91,i = 92,i = 92,i = 88,i = 63,i = 93,i = 64,i = 89,i = 93,i = 93,i = 94,i = 90,i = 65,i = 66,i = 67,i = 94,i = 95,i = 96,i = 97,i = 98,i = 99,i = 68,i = 91,i = 95,i = 96,i = 97,i = 98,i = 99,
i = 94,i = 95,i = 96,i = 97,i = 98,i = 99,
i = 92,i = 93,i = 94,i = 69,i = 70,i = 71,i = 72,i = 73,i = 74,i = 75,i = 76,i = 77,i = 78,i = 79,i = 80,i = 81,i = 82,i = 83,i = 84,i = 85,i = 86,i = 87,i = 88,i = 89,
i = 90,i = 91,i = 92,i = 93,i = 94,i = 95,i = 96,i = 97,i = 95,i = 96,i = 97,i = 98,i = 98,i = 99,
i = 99,
调用awaitTermination之前:true
调用awaitTermination之后:true
子线程执行完毕
主线程开始

 

其他:
1、 让主线程等待,或着睡眠几分钟。用Thread.sleep()或者TimeUnit.SECONDS.sleep(5);

如下:

package andy.thread.traditional.test;
 
import java.util.concurrent.TimeUnit;
 
/**
 * @author Zhang,Tianyou
 * @version 2014年11月21日 下午11:15:27
 */
 
public class ThreadSubMain1 {
 
  public static void main(String[] args) {
    // TODO Auto-generated method stub
 
    for (int i = 0; i < 10; i++) {
 
      new Thread(new Runnable() {
        public void run() {
 
          try {
            Thread.sleep(1000);
            // 模拟子线程任务
          } catch (InterruptedException e) {
          }
          System.out.println("子线程" + Thread.currentThread() + "执行完毕");
 
        }
      }).start();
      
    }
 
    try {
      // 等待全部子线程执行完毕
      TimeUnit.SECONDS.sleep(5);
    } catch (InterruptedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
 
    System.out.println("主线执行。");
  }
 
}

 

子线程Thread[Thread-1,5,main]执行完毕
子线程Thread[Thread-3,5,main]执行完毕
子线程Thread[Thread-5,5,main]执行完毕
子线程Thread[Thread-7,5,main]执行完毕
子线程Thread[Thread-9,5,main]执行完毕
子线程Thread[Thread-0,5,main]执行完毕
子线程Thread[Thread-2,5,main]执行完毕
子线程Thread[Thread-4,5,main]执行完毕
子线程Thread[Thread-6,5,main]执行完毕
子线程Thread[Thread-8,5,main]执行完毕
主线执行。

 

此方主线程只是睡了5秒,但是不能保证全部的子线程执行完成,所以这儿的5秒只是一个估值

2 、使用Thread的join()等待所有的子线程执行完毕,主线程在执行

实现 如下

package andy.thread.traditional.test;
 
import java.util.Vector;
 
/**
 * @author Zhang,Tianyou
 * @version 2014年11月21日 下午11:15:27
 */
 
public class ThreadSubMain2 {
 
  public static void main(String[] args) {
    // 使用线程安全的Vector 
    Vector<Thread> threads = new Vector<Thread>();
    for (int i = 0; i < 10; i++) {
 
      Thread iThread = new Thread(new Runnable() {
        public void run() {
 
          try {
            Thread.sleep(1000);
            // 模拟子线程任务
          } catch (InterruptedException e) {
          }
          System.out.println("子线程" + Thread.currentThread() + "执行完毕");
 
        }
      });
 
      threads.add(iThread);
      iThread.start();
    }
 
    for (Thread iThread : threads) {
      try {
        // 等待所有线程执行完毕
        iThread.join();
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
 
    System.out.println("主线执行。");
  }
 
}

执行结果:

子线程Thread[Thread-1,5,main]执行完毕
子线程Thread[Thread-2,5,main]执行完毕
子线程Thread[Thread-0,5,main]执行完毕
子线程Thread[Thread-3,5,main]执行完毕
子线程Thread[Thread-4,5,main]执行完毕
子线程Thread[Thread-9,5,main]执行完毕
子线程Thread[Thread-7,5,main]执行完毕
子线程Thread[Thread-5,5,main]执行完毕
子线程Thread[Thread-8,5,main]执行完毕
子线程Thread[Thread-6,5,main]执行完毕
主线执行。
posted @ 2021-02-07 00:32  纵码万水千山  阅读(4244)  评论(0编辑  收藏  举报