线程池

Java线程池(废弃)

服务器会接受大量请求(每个请求一个线程),若线程很多但是服务时间很短,则会频繁的创建/销毁线程,这会极大的降低系统效率。

为什么要使用线程池

  • 降低线程创建/销毁的资源消耗
  • 提高线程的可管理性(数量/分配/监控等)

利用Executors创建不同的线程池满足不同场景的需求

1
2
3
4
5
6
7
8
9
10
11
12
13
newFixedThreadPool(int nThreads);	// 指定工作线程固定数量的线程池

newCachedThreadPool(); // 处理大量短时间工作任务的线程池,
// 1) 试图缓存线程并重用,当无缓存线程可用时,就会创建新的工作线程;
// 2) 如果线程闲置的时间超过阈值,则会被终止并移出缓存;
// 3) 系统长时间限制的时候,不会消耗资源
newSingleThreadExecutor(); // 创建唯一的工作者线程来执行任务,如果线程异常结束,会有另一个线程取代它

newSingleThreadScheduledExecutor(); & newScheduledThreadPool(int corePoolSize);
//定时或者周期性的工作调度

newWorkStealingPool(); // 内部会构建ForkJoinPool,利用working-stealing算法
// 并行的处理任务,不保证处理顺序

Fork/Join框架

  • 把大任务分割成若干个小任务并行执行,最终汇总每个小任务结果后得到大任务结果的框架

    Work-Stealing算法

    • 某个线程从其他队列里窃取任务来执行

J.U.C的三个Executor接口

java.util.concurrent;

  • Executor:运行新任务的简单接口,将任务提交和任务执行细节解耦

    1
    2
    3
    4
    5
    6
    // 传统线程启动方法
    Thread t = new Thread();
    t.start();
    // Executor接口启动方法
    Thread t = new Thread();
    executor.execute(t);
  • ExecutorService:具备管理执行器和任务生命周期的方法,提交任务机制更完善

  • ScheduledExecutorService:支持Future和定期执行的任务

ThreadPoolExecutor的构造函数

  • corePoolSize:核心线程数量
  • maximumPoolSize:线程不够用时能够创建的最大线程数
  • workQueue:任务等待队列(任务提交时,线程数量已经大于corePoolSize,则把该任务放进workQueue等待)
  • keepAliveTime:线程池维护线程允许的空闲时间,线程数量大于corePoolSize时,若没有新线程提交,则核心线程以外的线程不会被立即销毁,而是等待keepAliveTime时间再销毁。抢占的顺序不一定,看运气
  • threadFactory:创建新线程,Executors.defaultThreadFactory(),优先级相同、非守护
  • handler:线程池的饱和策略。当线程池满了之后的策略
    • AbortPolicy:直接抛出异常,默认策略
    • CallerRunsPolicy:用调用者所在的线程来执行任务
    • DiscardOldestPolicy:丢弃队列中最靠前的任务,并执行当前任务
    • DiskcardPolicy:直接丢弃本任务
    • 也可以实现RejectedExecutionHandler接口的自定义handler

新任务提交execute执行后的判断

  • 如果运行的线程少于corePoolSize,则创建新线程来处理任务,即使线程池中的其他线程是空闲的;
  • 如果线程池中的线程数量大于等于corePoolSize且小于maximumPoolSize,则只有当workQueue满时才创建新的线程去处理任务;
  • 如果设置的corePoolSize和maximumPoolSize相同,则创建的线程池的大小是固定的,这是如果有新任务提交,若workQueue未满,则将请求放入workQueue中,等待有空闲的线程从workQueue中取任务并处理;
  • 如果运行的线程数量大于等于maximumPoolSize,这时如果workQueue也满了,则通过handler所指定的策略来处理任务。

线程池的状态

  • RUNNING:能接受新提交的任务,并且也能处理阻塞队列中的任务

  • SHUTDOWN:不再接受新提交的任务,但可以处理存量任务

  • STOP:不再接受新提交的任务,也不处理存量任务

  • TIDYING:所有任务都已终止

  • TERMINATED:terminated()方法执行完后为该状态

    状态转移图

工作线程的生命周期

工作线程的生命周期

线程池的大小如何选定

  • CPU密集型:线程数= CPU核心数量+1设定
  • I/O密集型:线程数 = CPU核心数量 * (1 + 平均等待时间/平均工作时间)
Ty.Wings wechat
欢迎您订阅我的公众号,并在GitHub上为我Star!