多线程 -- 线程池

多线程 -- 线程池

1. 作用

  • 重用线程, 减少线程创建销毁带来的开销;
  • 限制最先线程并发数目, 避免大量线程之间因相互抢占系统资源而导致的阻塞现象;

2. 创建与使用

通常我们通过Executors类提供的工厂方法创建线程池;
而线程池的实际实现是ThreadPoolExecutor, 它提供一系列的参数来配置线程池;
我们通过ExecutorService去管理线程池, 用它去提交任务, 关闭线程池; 它是一个接口, ThreadPoolExecutor实现了该接口;
我们提交任务给线程池去执行, 而任务由Executor(执行器)去提交, Executor是一个接口, ExecutorService又继承了该接口;

2.1 ThreadPoolExecutor

线程池的实际实现, 它的构造方法提供了一系列的参数用于我们配置线程池;

  ThreadPoolExecutor(int corePoolSize,
                    int maximumPoolSize,
                    long keepAliveTime,
                    TimeUnit unit,
                    BlockingQueue workQueue,
                    ThreadFactory threadFactory,
                    RejectedExecutionHandler handler);
corePoolSize & maximumPoolSize (核心和最大池大小)

当新任务在方法 execute(java.lang.Runnable) 中提交时,如果运行的线程少于 corePoolSize,则创建新线程来处理请求,即使其他辅助线程是空闲的。如果运行的线程多于 corePoolSize 而少于 maximumPoolSize,则仅当队列满时才创建新线程;

keepAliveTime & unit (保持活动时间)

如果池中当前有多于 corePoolSize 的线程,则这些多出的线程在空闲时间超过 keepAliveTime 时将会终止;
默认情况下, 核心线程会一直存活, allowCoreThreadTimeOut(boolean)设置为true时, 超时策略同样会作用于核心线程;

workQueue (工作队列)

线程池中的工作队列; 通过execute提交的Runnable都会保存在这儿; 具体情况如下:

  • 如果运行的线程少于 corePoolSize,则 Executor 始终首选添加新的线程,而不进行排队。(如果当前运行的线程小于corePoolSize,则任务根本不会存放,添加到queue中,而是直接抄家伙(thread)开始运行)
  • 如果运行的线程等于或多于 corePoolSize,则 Executor 始终首选将请求加入队列,而不添加新的线程
  • 如果无法将请求加入队列,则创建新的线程,除非创建此线程超出 maximumPoolSize,在这种情况下,任务将被拒绝。
threadFactory

线程工厂; 为线程池提供Thread对象; 可以自定义ThreadFactory, 为线程池中的thread添加属性;

RejectedExecutionHandler

当线程池已经关闭, 或者任务队列已满而无法执行新任务时, execute会调用RejectedExecutionHandler去处理;
默认情况下, 会直接抛出 RejectedExecutionExecption ;

hook方法

可重写的 beforeExecute(Runnable) 和 afterExecute(Throwable) 方法,这两种方法分别在执行每个任务之前和之后调用。
它们可用于操纵执行环境;例如重新初始化 ThreadLocal、搜集统计信息或添加日志条目。此外,还可以重写方法 terminated() 来执行 Executor 完全终止后需要完成的所有特殊处理;

3 Executors

Executors 系统系统的线程池的工厂方法; 可以产生如下几种常用的线程池;

  • newCachedThreadPool 无核心线程,辅助线程无上限, 超时60s的线程池
  • newFixedThreadPool 固定线程数的线程池
  • newSingleThreadExecutor 只有一个线程, 所有任务单个依次执行
  • newScheduledThreadPool 可以提交延迟任务,或者定期任务的线程池
  • newSingleThreadScheduledExecutor

4 使用方法

  1. 创建一个线程池, 使用Executors中的静态方法创建一个线程池
  2. 调用submit方法提交一个Runnable或者Callable对象
  3. 如果要取消一个任务, 或如果提交的是Callable对象, 就需要保存好返回的Future对象
  4. 当不再提交任何任务时, 调用shutdown方法

你可能感兴趣的:(多线程 -- 线程池)