• Java多线程之ExecutorService使用说明


    一、简介

    ExecutorService是Java中对线程池定义的一个接口,它java.util.concurrent包中,在这个接口中定义了和后台任务执行相关的方法。

    二、线程池

    Java给我们提供了一个Executors工厂类,它可以帮助我们很方便的创建各种类型ExecutorService线程池,Executors一共可以创建下面这四类线程池:

    • newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。 
    • newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。 
    • newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。 
    • newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

    三、代码举例

    import org.junit.Test;
    import java.util.concurrent.*;
    
    /**
     * @author :gongxr
     * @description:ExecutorService是Java中对线程池定义的一个接口,它java.util.concurrent包中,在这个接口中定义了和后台任务执行相关的方法。 Java通过Executors提供四种创建线程池的工厂类,分别为:
     * newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
     * newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
     * newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
     * newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
     */
    
    public class TestExecutorService {
        /**
         * newCachedThreadPool:创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
         */
        @Test
        public void test1() throws InterruptedException {
            ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    try {
                        System.out.println(Thread.currentThread().getName() + " 开始工作!");
                        Thread.sleep((long) (Math.random() * 3000));
                        System.out.println(Thread.currentThread().getName() + " 工作结束!");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            };
            for (int i = 0; i < 5; i++) {
                cachedThreadPool.execute(runnable);
            }
            Thread.sleep(3000);
            System.out.println("主线程结束!");
            cachedThreadPool.shutdown();
        }
    
        /**
         * newFixedThreadPool:创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
         */
        @Test
        public void test2() throws InterruptedException {
            ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    try {
                        System.out.println(Thread.currentThread().getName() + " 开始工作!");
                        Thread.sleep((long) (Math.random() * 3000));
                        System.out.println(Thread.currentThread().getName() + " 工作结束!");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            };
            for (int i = 0; i < 6; i++) {
                final int index = i;
                fixedThreadPool.execute(runnable);
            }
            Thread.sleep(6000);
            fixedThreadPool.shutdown();
            System.out.println("主线程结束!");
        }
    
        /**
         * newScheduledThreadPool:创建一个定长线程池,支持定时及周期性任务执行。
         * 该例中延迟3秒执行。
         */
        @Test
        public void test3_1() throws InterruptedException {
            ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3);
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    System.out.println("delay 3 seconds");
                }
            };
            scheduledThreadPool.schedule(runnable, 3, TimeUnit.SECONDS);
            Thread.sleep(10000);
            scheduledThreadPool.shutdown();
        }
    
        /**
         * newScheduledThreadPool:创建一个定长线程池,支持定时及周期性任务执行。
         * 延迟1秒后每3秒执行一次。
         */
        @Test
        public void test3_2() throws InterruptedException {
            ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3);
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    System.out.println("delay 1 seconds, and excute every 3 seconds");
                }
            };
            scheduledThreadPool.scheduleAtFixedRate(runnable, 1, 3, TimeUnit.SECONDS);
            Thread.sleep(10000);
            scheduledThreadPool.shutdown();
        }
    
        /**
         * newSingleThreadExecutor:创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
         */
        @Test
        public void test4() throws InterruptedException {
            ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
            for (int i = 0; i < 5; i++) {
                final int index = i;
                singleThreadExecutor.execute(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            System.out.println(index);
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                });
            }
            Thread.sleep(10000);
            singleThreadExecutor.shutdown();
        }
    
        /**
         * submit(Callable)
         * submit(Callable)和submit(Runnable)类似,也会返回一个Future对象,
         * 但是除此之外,submit(Callable)接收的是一个Callable的实现,
         * Callable接口中的call()方法有一个返回值,可以返回任务的执行结果,
         * 而Runnable接口中的run()方法是void的,没有返回值。
         */
        @Test
        public void testCallable() throws Exception {
            ExecutorService executorService = Executors.newCachedThreadPool();
            Callable callable = new Callable() {
                @Override
                public Object call() throws InterruptedException {
                    String name = Thread.currentThread().getName();
                    System.out.println("Thread Name:" + name + " 开始工作!");
                    Thread.sleep((long) (Math.random() * 3000));
                    System.out.println("Thread Name:" + name + " 结束工作!");
                    return name;
                }
            };
    
            Future future = executorService.submit(callable);
    
            System.out.println("主线程继续执行!");
            Thread.sleep(3000);
    
            // future.get()使得主线程阻塞,等待子线程执行结束
            System.out.println("子线程执行完回调结果:" + future.get().toString());
    
            System.out.println("主线程结束!");
            executorService.shutdown();
        }
    
        /**
         * ExecutorService的shutdown、shutdownNow、awaitTermination用法:
         * 调用shutdown方法之后,ExecutorService不再接收新的任务,直到当前所有线程执行完成才会关闭,所有之前提交的任务都会被执行。
         * 调用shutdownNow方法后,将试图阻止所有正在执行的任务和被提交还没有执行的任务。
         * awaitTermination方法的作用:监视各任务的状态是否已经结束,经过指定的时间后,全部完成返回true,反之返回false。
         */
        @Test
        public void testShutDown() throws Exception {
            ExecutorService executorService = Executors.newCachedThreadPool();
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    try {
                        System.out.println(Thread.currentThread().getName() + " 开始工作!");
                        Thread.sleep(2000);
                        System.out.println(Thread.currentThread().getName() + " 工作结束!");
                    } catch (InterruptedException e) {
                        System.out.println(Thread.currentThread().getName() + " 子线程中断!");
                        e.printStackTrace();
                    }
                }
            };
            // 线程1
            executorService.execute(runnable);
            Thread.sleep(1000);
            // 线程2
            executorService.execute(runnable);
            executorService.shutdown();
            // 等待一秒后检查子线程运行状态,全部完成返回true
            if (!executorService.awaitTermination(1, TimeUnit.SECONDS)) {
                System.out.println("主线程强制中断子线程!");
                executorService.shutdownNow();
            }
            Thread.sleep(4000);
            System.out.println("主线程结束!");
        }
    
    }

    与多线程同步工具结合使用:

        /**
         * ExecutorService实战用法:
         * 与CountDownLatch线程同步工具结合使用
         */
        @Test
        public void testExe() throws Exception {
            int count = 5; // 任务数量
            ExecutorService executorService = Executors.newCachedThreadPool();
            CountDownLatch countDownLatch = new CountDownLatch(count);  //线程同步工具
    
            for (int i = 1; i <= count; i++) {
                int taskId = i;
                executorService.execute(() -> task(taskId, countDownLatch));
            }
    
            executorService.shutdown();  // 不再接受新任务
            countDownLatch.await();  // 等待所有任务完成
            // 等待一秒后检查子线程运行状态,全部完成返回true
            if (!executorService.awaitTermination(1, TimeUnit.SECONDS)) {
                System.out.println("主线程强制中断子线程!");
                executorService.shutdownNow();
            }
            System.out.println("主线程结束!");
        }
    
        private void task(int index, CountDownLatch countDownLatch) {
            try {
                System.out.println("任务" + index);
                System.out.println(Thread.currentThread().getName() + " 开始工作!");
                Thread.sleep((long) (Math.random() * 3000));
                System.out.println(Thread.currentThread().getName() + " 工作结束!");
                countDownLatch.countDown();
            } catch (InterruptedException e) {
                System.out.println(Thread.currentThread().getName() + " 子线程中断!");
                e.printStackTrace();
            }
        }

     运行结果:

    任务1
    任务3
    任务4
    pool-1-thread-4 开始工作!
    任务2
    pool-1-thread-2 开始工作!
    任务5
    pool-1-thread-3 开始工作!
    pool-1-thread-1 开始工作!
    pool-1-thread-5 开始工作!
    pool-1-thread-3 工作结束!
    pool-1-thread-2 工作结束!
    pool-1-thread-5 工作结束!
    pool-1-thread-4 工作结束!
    pool-1-thread-1 工作结束!
    主线程结束!
  • 相关阅读:
    Codeforces 1354C2
    Codeforces 1354C1
    Codeforces 1355C
    Codeforces 1353D
    Codeforces 1352
    Codeforces 1351C
    Codeforces 1344B/1345D
    Codeforces 1342D
    Codeforces 1340B/1341D
    Codeforces 1343D
  • 原文地址:https://www.cnblogs.com/gongxr/p/14463568.html
Copyright © 2020-2023  润新知