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 工作结束!
主线程结束!

 

posted @ 2021-03-01 14:50  星瑞  阅读(3538)  评论(0编辑  收藏  举报