Java线程池

api reference:https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ThreadPoolExecutor.html

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler)

corePoolSize-即便他们空闲,池中保持的线程数,除非设计了allowCoreThreadTimeOut
maximumPoolSize-最大线程数
keepAliveTime-线程数超过core,其余的等待新任务的空闲线程销毁前等待的最大时间
unit-keepAliveTime参数的时间单位
workQueue-在执行前存放任务的队列。队列仅存放execute方法提交的Runnable
threadFactory-用于产生新线程
handler-当线程数量和队列容量到达时,处理堵塞的策略

当一个新任务提交并且线程数低于corePoolSize时,创建新线程处理请求,无论其他线程是否空闲。如果比corePoolSize多比maximumPoolSize少,只有队列满才会创建新线程。设置两个size相同,创建了一个固定数量线程池。设置max到类似MAX_VALUE的无边界值,允许池容纳任意数量并发任务。可以被动态改变,使用setCorePoolSize(int)/setMaximumPoolSize(int)

默认情况,当新任务来时core线程才会创建和启用,但可以被prestartCoreThread()/prestartAllCoreThreads()动态覆盖

新线程用ThreadFactory创建。默认使用Executors.defaultThreadFactroy(),创建的线程全部在相同的ThreadGroup/相同的NORM_PRIORITY优先级/非daemon状态。通过用不同的ThreadFactory,可以修改线程名,线程组,优先级,daemon状态。

如果池有超过coresize线程,当额外线程的空闲时间超过keepAliveTime将会被中止。这可以在池不活跃时减少资源使用。使用大数值可以避免空闲线程被中止。默认情况policy只用于多余coresize。allowCoreThreadTimeout(boolean)可以把policy用于core threads

queuing的三种常见策略:

  • 直接推开。SynchronousQueue,将任务直接交给线程,不持有。如果没有线程能立即运行,入队任务会失败,新线程会被创建。处理有内部依赖的一些请求时,该policy避免了锁定。直接推开一般需要无界maxsize来避免拒绝新提交任务。当命令来的速度快于被处理的速度时,这允许无界线程增长的可能
  • 无界queues.LinkedBlockingQueue不带预定义容量。使用无界队列将导致,所有core thread繁忙时,新任务入队等待。因此,没有更多线程被创建,maxSize无用。当每个任务完全独立时适用,任务不影响其他执行,比如web page server。也可以用于平滑请求,允许无界队列增长的可能,当命令持续到来的速度快于他们被处理的速度。
  • 有界队列。ArrayBlockingQueue。当使用有限maxSIze时帮助阻止资源耗尽,较难调整和控制。queue size和maxSize需要权衡:大queue小pool使CPU/OS资源/上下文切换成本最低,也带来低吞吐量。如果任务频繁block(比如IO),系统可能能为更多线程调度时间。小queue大pool,使CPU繁忙,但有不可接受的调度成本,也降低了吞吐量

当Executor被关闭,使用了有限maxSize和queue容量,新提交任务会被reject。4种预定义处理polcy:

  • default AboutPolicy,throws a runtime RejectedExecutionExecption
  • CallerRunsPlicy,调用execute的线程执行任务,提供了一个简单的反馈控制机制,用于降低新任务提交的频率
  • DiscardPolicy,无法执行的任务简单丢掉
  • DiscardOldestPolicy,queue头部任务被丢掉

beforeExecute(Thread,Runnable) afterExecute(Runnable,Throwable),在每个任务执行前后被调用,可用于管理执行环境,比如,重初始化ThreadLocals,收集静态信息,log。terminated()可被重载用于执行特殊过程

getQueue()允许为monitor和debug访问queue,其他目的不推荐。remove(Runnable),purge()可用于取消大量任务来回收内存
在这里插入图片描述

Executor4个便利的工厂方法

线程无界
在这里插入图片描述
在这里插入图片描述

队列无界
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

池的好处:降低资源消耗,提高响应速度,提高线程可管理性

在这里插入图片描述

1.主线程首先要创建实现 Runnable 或者 Callable 接口的任务对象。
2.把创建完成的实现 Runnable/Callable接口的 对象直接交给 ExecutorService 执行: ExecutorService.execute(Runnable command))或者也可以把 Runnable 对象或Callable 对象提交给 ExecutorService 执行(ExecutorService.submit(Runnable task)或 ExecutorService.submit(Callable task))。
3.如果执行 ExecutorService.submit(…),ExecutorService 将返回一个实现Future接口的对象(我们刚刚也提到过了执行 execute()方法和 submit()方法的区别,submit()会返回一个 FutureTask 对象)。由于 FutureTask 实现了 Runnable,我们也可以创建 FutureTask,然后直接交给 ExecutorService 执行。
4.最后,主线程可以执行 FutureTask.get()方法来等待任务执行完成。主线程也可以执行 FutureTask.cancel(boolean mayInterruptIfRunning)来取消此任务的执行。

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值