线程池的使用

290 阅读2分钟

使用线程池的益处

  • 避免重复创建线程执行任务,减少了创建线程和销毁线程需要的时间开销和性能开销;
  • 提高任务响应速度,线程池中通常缓存有线程,当提交任务以后,可迅速执行;
  • 避免了无规则的创建大量线程,导致大量线程排队等待CPU,响应速度变慢;

线程池处理流程

stage.png

我们可以调用线程池的execute和submit方法来提交任务,提交参数都是一个Runnable实例,不同的是,submit会返回一个Future类型的对象,可以通过future对象的get方法获得返回值,注意这个方法会阻塞当前线程。

  1. 当一个任务提交给线程池时,如果当前线程池中线程数量少于核心线程数,会重新创建新的线程执行这个任务,然后通过线程安全的方法更新当前线程数。注意,当提交一个任务给线程池时,线程池会创建一个核心线程来执行,即使其他核心线程空闲,直到核心线程达到预设值。
  2. 如果当前线程数已经大于或者等于核心线程数,那会尝试判断阻塞队列是否已满,未满的话将任务加入到阻塞队列中。
  3. 已满则判断当前线程池数量是否小于最大线程数量,如果是的话,创建工作线程执行,否则的话执行拒绝策略。

线程池参数说明

public ThreadPoolExecutor(int corePoolSize,//核心线程数
                          int maximumPoolSize, //最大工作线程数,不能小于corePoolSize
                          long keepAliveTime, //非核心线程超时时间,闲置时间超过会被销毁
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue, //用于保存等待执行的任务的阻塞队列
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler //拒绝策略)

阻塞队列有很多种,newCachedThreadPool使用SynchronousQueue,这种阻塞队列不存储任务,每个插入操作必须等待一个线程执行取出操作,否则插入线程阻塞。newFixedThreadPool则使用LinkedBlockingQueue。

handle.png

拒接策略分为四种,分别是直接只用调用者所在线程执行任务、直接抛出异常、丢弃队列里等待最长时间的任务,执行当前任务、或者直接丢弃掉当前任务。

配置线程池

根据不同的情况配置线程池:

  • 根据任务性质,比如是CPU密集型还是IO密集型,CPU密集型应该配置尽可能少的线程,防止线程持续等待CPU分配时间,IO密集型就可以多一些线程,因为大部分线程可能在等待IO;
  • 任务优先级,是否有些任务是高优执行的,可以使用ProrityQueue作为阻塞队列。