接口 Executor
↑ 继承
接口 ExecutorService
↑实现
抽象类 AbstractExecutorService
↑继承
实类 ThreadPoolExecutor 工具类 Executors
ExecutorService pool = Executors.newSingleThreadExecutor() ;
pool.submit(new Thread());
在真正执行时,
1.如果运行的线程数小于corePoolSize, 那么任务将直接操家伙(new Thread)执行。
2.如果运行的线程大于或等于coerPoolSize,那么任务将被添加进队列。
3.如果无法请求添加进入队列,那么就再new Thread,然后执行。
4.如果此时的线程数量已经大于等于maximumPoolSize,此次任务将会被拒绝。
keepAliveTime,这个参数特殊说明一下,就是超过coerPoolSize的线程数,是借来使用的,我们必须还,就在这些线程空闲keepAliveTime以后就还呗。
在实际运用中,就得权衡 队列大小和线程池大小。
直接提交:maximumPoolSizes 无界,就不会将任务添加进队列
无界队列:LinkedBlockingQueue,此时,任务可以无限添加进队列,但可能corePoolSize线程都处于运行状态。
有界队列:有限的maximumPoolSizes,有界队列ArrayBlockingQueue。有助于防止资源耗尽,但是可能较难调整和控制。队列大小和最大池大小可能需要相互折衷;使用大队列和小型池可以最大限度的降低CPU使用率,操作系统资源和上下文切换的开销,但是可能导致人工降低吞吐率,如果任务频繁阻塞,那还不如多几个线程呢,对吧。使用小队列通常要求较大的池大小,CPU使用率较高,但是可能遇到不可接受的调度开销(线程切换开销很大的),这样也会降低吞吐率。
RejectedExecutionHandler 处理者的各种策略
1.CallerRunsPolicy不想抛弃任务,直接使用调用execute的线程来执行。
2.AbortPolicy丢任务,抛异常
3.DiscardPolicy丢任务,不抛异常
4.DiscardOldestPolicy:如果执行程序尚未关闭,则位于工作队列头部的任务将被删除,然后重试执行程序(如果再次失败,则重复此过程)