并发编程 系列 线程池

开启 并发编程 新篇章

Posted by lichao modified on May 16, 2020

先看一下线程池的类图: jvm

Executor

Executor 是执行提交的 Runable 任务 的执行器。 这个接口提供了一种机制,使得 task 的提交和 task 如何执行被运行(包括线程的使用和分配)的相分离: jvm

ExecutorService

ExecutorService 是 Executor 直接的扩展接口,也是最常用的线程池接口,通见的线程池与定时任务线程池都是它的实现类。

  • void shutdown(): 在关闭 ExecutorService 之前等待提交的任务执行完成
  • List<Runnable>shutdownNow(): shutdownNow方法会阻止开启新的任务并且尝试停止当前正在执行的线程,尝试停止所有的正在执行的任务,避免处理所有正在等待执行的任务,返回这些等待的任务
  • boolean isTerminated(); // 当调用shutdown()后,所有的task已经完成,则返回true;(首次应调用shutdown或shutdownNow)
  • boolean awaitTermination(long timeout,TimeUnit unit)。当调用shutdown()之后,阻塞直到所有的task完成;除非时间耗尽;
  • <T>Future<T> submit(Callable<T> task); 提交一个有返回值的task,返回一个future,代表将要获得的结果;这个future的get方法返回task的结果
  • <T> List <Future<T>> invokeAll(Collection< ? extends Callable<T> > tasks) throws InterruptedException; //执行多个task,返回多个future来获取结果; 注意: 如果在处理过程中,collection发生了变化,结果不确定;
  • <T>T invokeAny(Collection< ? extendsCallable <T> > tasks)执行给定的任务列表,直到有一个成功的返回值;

ExecutorCompletionService

主要思想是把处理结果放到了队列里面; 线程池结果管理器:ExecutorCompletionService。它将 BlockingQueue 和 Executor 封装起来。然后使用ExecutorCompletionService.submit()方法提交任务。

Executors

Executors 是一个生产线程池对象的工厂

提供了四种线程池:

  1. Executors.newCachedThreadPool 创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。线程池为无限大,当执行第二个任务时第一个任务已经完成,会复用执行第一个任务的线程,而不用每次新建线程: jvm 注:保活时间为60秒;
  2. Executors.newFixedThreadPool (int nThresds)创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。定长线程池的大小最好根据系统资源进行设置。如Runtime.getRuntime().availableProcessors() jvm

  3. Executors.newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。ScheduledExecutorService比Timer 更安全,功能更强大,后面会有一篇单独进行对比。 jvm

  4. Executors.newSingleThreadExecutor() 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。顺序执行各个任务。 jvm

种类

定时周期任务线程池

提供一个执行服务,能够在指定的延迟后或周期性的执行命令

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class WorkerThread implements Runnable {
    @Override
    public void run() {

    }
}

/** 
 * scheduleWithFixedDelay 中的 delayTime 
 * 代表每次线程任务执行完毕后,直到下一次开始执行开始之前的时间间隔。
 */
public static void scheduleWithDelay() { 
  ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3); 
 WorkerThread workerThread = new WorkerThread("do some thing"); scheduledExecutorService.scheduleWithFixedDelay(workerThread, 3000, 3000, TimeUnit.MILLISECONDS);
}

/** 
 * scheduleAtFixedRate 中的 delayTime/period 表示从线程池中首先开始执行的线程算起,假设period为1s, 
 * 若线程执行了5s,那么下一个线程在第一个线程运行完后会很快被执行。 
 */ 
public static void scheduleAtRate() { 
 ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3);
 WorkerThread workerThread = new WorkerThread("do some thing"); 
  scheduledExecutorService.scheduleAtFixedRate(workerThread, 3000, 3000, TimeUnit.MILLISECONDS); 
}