使用java线程池ExecutorService,执行多线程操作,使用CountDownLatch来保证多线程执行完毕之后,再释放线程池

新建一个类测试并发使用:

public class runDo {

    private long id;

    private String name;

    private String env;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEnv() {
        return env;
    }

    public void setEnv(String env) {
        this.env = env;
    }
}

新建测试类:设置不同的线程池 和 计数器 查看执行情况

public class TestRunnable {

    static long num = 0;

    public static void main(String args[]) {

        System.out.println(getNum());
    }

    public static long getNum(){

        int count = 20;
        // 计数器  构造指定数量的CountDownLatch
        CountDownLatch end = new CountDownLatch(count);

        // 创建线程池,可设置最大并发数 超出的线程会 等待 其中一个执行完成
        ExecutorService exec = Executors.newFixedThreadPool(10);

        // 创建单一线程池,等于一个线程执行,顺序执行
        //ExecutorService exec = Executors.newSingleThreadExecutor();

        // 创建一个线程池,根据需要创建线程,线程执行完 可以继续复用
        //ExecutorService exec = Executors.newCachedThreadPool();

        List<runDo> list = new ArrayList<>();
        for (int i = 1; i <= 10; i++) {
            runDo rundo = new runDo();
            rundo.setId(i);
            rundo.setName("name" + i);
            rundo.setEnv("env" + i);
            list.add(rundo);
        }

        for (runDo rundo : list) {
            Runnable run = new MyRunnableTest(rundo, end);
            //线程池一共10个线程, 多线程执行
            exec.execute(run);
            //返回 线程执行 耗时长 则 这里count 都为 20
            //System.out.println("——计数器:"+ end.getCount());
        }

        try {
            // 当前线程等待,直到计数器递减至零为止,除非该线程被中断
            //end.await();

            //当前线程等待,直到计数器到递减零为止,除非该线程被中断或经过了指定的等待时间
            //总的计数器 大于 执行次数时候,需要设置超时 时间, 可以设置 时间单位
            end.await(5, TimeUnit.SECONDS);
            System.out.println("已经等待5s");

        } catch (Exception e) {
            e.printStackTrace();
        }
        // 关闭线程池 等待执行完成 ,不接受新任务
        exec.shutdown();
        return  num ;
    }

    static class MyRunnableTest implements Runnable {

        runDo rundo;
        CountDownLatch end;

        public MyRunnableTest(runDo rundo, CountDownLatch end) {
            this.rundo = rundo;
            this.end = end;
        }

        @Override
        public void run() {

            num = rundo.getId()+num;
            try {
                 //Thread.sleep(3);
                // System.out.println("可以查看newSingleThreadExecutor的情况下是否依此等待");
            }catch (Exception e){
                e.printStackTrace();
            }
            // end.toString():返回一个标识此锁存器及其状态的字符串
            // end.getCount():返回当前计数 剩余的
            System.out.println(Thread.currentThread().getName() +"——NUM:"+ num +"——"+ end.toString()+"——计数器:" +end.getCount());

            // 减少锁存器的计数,如果计数达到零,则释放所有等待线程 ,如果到达零,则无影响
            end.countDown();
        }
    }
}

当前测试控制台输出:

1、线程池 一共10个线程,NUM值最终为55,计数器没有到0等待5秒再继续执行

pool-1-thread-2——NUM:3——java.util.concurrent.CountDownLatch@76f1ebbf[Count = 20]——计数器:20
pool-1-thread-4——NUM:10——java.util.concurrent.CountDownLatch@76f1ebbf[Count = 20]——计数器:20
pool-1-thread-3——NUM:6——java.util.concurrent.CountDownLatch@76f1ebbf[Count = 20]——计数器:20
pool-1-thread-1——NUM:3——java.util.concurrent.CountDownLatch@76f1ebbf[Count = 20]——计数器:20
pool-1-thread-6——NUM:21——java.util.concurrent.CountDownLatch@76f1ebbf[Count = 17]——计数器:17
pool-1-thread-5——NUM:15——java.util.concurrent.CountDownLatch@76f1ebbf[Count = 20]——计数器:19
pool-1-thread-7——NUM:28——java.util.concurrent.CountDownLatch@76f1ebbf[Count = 14]——计数器:14
pool-1-thread-8——NUM:36——java.util.concurrent.CountDownLatch@76f1ebbf[Count = 13]——计数器:13
pool-1-thread-9——NUM:45——java.util.concurrent.CountDownLatch@76f1ebbf[Count = 12]——计数器:12
pool-1-thread-10——NUM:55——java.util.concurrent.CountDownLatch@76f1ebbf[Count = 11]——计数器:11
已经等待5s
55

并发此时计数器不是依次减少的,将上面线程池改成

ExecutorService exec = Executors.newSingleThreadExecutor();

执行查看控制台输出:计数器依次减少

pool-1-thread-1——NUM:1——java.util.concurrent.CountDownLatch@a8f72d1[Count = 20]——计数器:20
pool-1-thread-1——NUM:3——java.util.concurrent.CountDownLatch@a8f72d1[Count = 19]——计数器:19
pool-1-thread-1——NUM:6——java.util.concurrent.CountDownLatch@a8f72d1[Count = 18]——计数器:18
pool-1-thread-1——NUM:10——java.util.concurrent.CountDownLatch@a8f72d1[Count = 17]——计数器:17
pool-1-thread-1——NUM:15——java.util.concurrent.CountDownLatch@a8f72d1[Count = 16]——计数器:16
pool-1-thread-1——NUM:21——java.util.concurrent.CountDownLatch@a8f72d1[Count = 15]——计数器:15
pool-1-thread-1——NUM:28——java.util.concurrent.CountDownLatch@a8f72d1[Count = 14]——计数器:14
pool-1-thread-1——NUM:36——java.util.concurrent.CountDownLatch@a8f72d1[Count = 13]——计数器:13
pool-1-thread-1——NUM:45——java.util.concurrent.CountDownLatch@a8f72d1[Count = 12]——计数器:12
pool-1-thread-1——NUM:55——java.util.concurrent.CountDownLatch@a8f72d1[Count = 11]——计数器:11
已经等待5s
55

Process finished with exit code 0

官方API:

https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CountDownLatch.html

https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html