如何创建线程池

[Q&A] 如何创建线程池?

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler) {
                          
    if (corePoolSize < 0 || maximumPoolSize <= 0 || maximumPoolSize < corePoolSize || keepAliveTime < 0)
        throw new IllegalArgumentException();
        
    if (workQueue == null || threadFactory == null || handler == null)
        throw new NullPointerException();
        
    this.corePoolSize = corePoolSize;
    this.maximumPoolSize = maximumPoolSize;
    this.workQueue = workQueue;
    this.keepAliveTime = unit.toNanos(keepAliveTime);
    this.threadFactory = threadFactory;
    this.handler = handler;
}
corePoolSize  
# 核心线程数,线程池的大小,the number of threads to keep in the pool, even if they are idle.

maximumPoolSize
# 线程池最大数量	          the maximum number of threads to allow in the pool.

keepAliveTime	
# when the number of threads is greater than the core, this is the maximum time that excess idle threads will wait for new tasks before terminating.

unit	
# 可选的单位有天(DAYS)、小时(HOURS)、分钟(MINUTES)、毫秒(MILLISECONDS)、微秒(MICROSECONDS,千分之一毫秒)和纳秒(NANOSECONDS,千分之一微秒)。

BlockingQueue<Runnable> workQueue	
# the queue to use for holding tasks before they are executed. This queue will hold only the Runnable tasks submitted by the execute method.

threadFactory
# 创建线程的工厂,the factory to use when the executor creates a new thread

RejectedExecutionHandler handler
# 拒绝策略,the handler to use when execution is blocked because the thread bounds and queue capacities are reached
# 当队列和线程池都满了,说明线程池处于饱和状态,那么必须采取一种策略处理提交的新任务。

线程池 饱和策略

线程池 任务队列

在这里插入图片描述

缓存型线程池 newCachedThreadPool

# newCachedThreadPool
ExecutorService exec = Executors.newCachedThreadPool();

public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
}

# 无界的线程池
# 适用于执行很多的短期异步任务的小程序,或者是负载较轻的服务器。

[Q&A] 为什么不推荐使用CachedThreadPool
maximumPoolSize被设置为 Integer.MAX.VALUE, 这也就意味着如果主线程提交任务的速度高于maximumPool中线程处理任务的速度时,CachedThreadPool 会不断创建新的线程。极端情况下,这样会导致耗尽cpu和内存资源,从而导致OOM


固定线程数量线程池 newFixedThreadPool

# newFixedThreadPool
ExecutorService exec = Executors.newFixedThreadPool(3);

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
}

# 无界的线程池
# 适用于为了满足资源管理的需求,而需要限制当前线程数量的应用场景,它适用于负载比较重的服务器。

[Q&A] 为什么不推荐使用FixedThreadPool
1、 当线程池中的线程数达到 corePoolSize 后,新任务将会添加到无界队列LinkedBlockingQueue中等待, 故 maximumPoolSize 将是一个无效参数。所以corePoolSize 和 maximumPoolSize 被设置为同一个值。 keepAliveTime 也是一个无效参数,因为 keepAliveTime 针对超过 corePoolSize 的线程起作用。
2、 运行中的 FixedThreadPool 不会拒绝任务(前提是未执行 shutdown()shutdownNow() )在任务比较多的时候会导致 OOM(内存溢出)。


单线程线程池 newSingleThreadExecutor

# newSingleThreadExecutor
ExecutorService exec = Executors.newSingleThreadExecutor();
public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1,1,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>()));
}
# 无界的线程池
# 用于需要保证顺序地执行各个任务;并且在任意时间点,不会有多个线程是活动的应用场景。

[Q&A] 为什么不推荐使用SingleThreadExecutor
SingleThreadExecutor 就是特殊的 FixedThreadPool ,理由如上


周期性线程池 newScheduledThreadPool

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
    return new ScheduledThreadPoolExecutor(corePoolSize);
}
public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
   return new DelegatedScheduledExecutorService(new ScheduledThreadPoolExecutor(1));
}

public class ScheduledThreadPoolExecutor extends ThreadPoolExecutor implements ScheduledExecutorService 
{
	public ScheduledThreadPoolExecutor(int corePoolSize) {
	    ThreadPoolExecutor (corePoolSize, Integer.MAX_VALUE, 10, TimeUnit.MILLI_SCALE, new DelayedWorkQueue());
	}
}
# newScheduledThreadPool   固定个数线程的调度线程池
# 用于需要多个后台线程执行周期任务,同时为了满足资源管理的需求而需要限制后台线程的数量的应用场景。
ScheduledThreadPoolExecutor exec = new ScheduledThreadPoolExecutor(1);
ScheduledThreadPoolExecutor exec = (ScheduledThreadPoolExecutor) Executors.newScheduledThreadPool(5);
ScheduledExecutorService exec = Executors.newScheduledThreadPool(2);

exec.schedule(() -> {执行}, 10, TimeUnit.SECONDS);                  // 延迟10秒执行
exec.scheduleWithFixedDelay(() -> {执行}, 1, 4, TimeUnit.SECONDS);  // 延迟 1s,间隔 4s
exec.scheduleAtFixedRate(() -> {执行}, 1, 4, TimeUnit.SECONDS)      // 延迟 1s,周期 4s
-----------------------------------------------------------------------------------------------
# newSingleThreadScheduledExecutor   单个线程的调度线程池
ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor();
ScheduledExecutorService exec = Executors.newScheduledThreadPool(1);
# 用于需要单个后台线程执行周期任务,同时需要保证顺序地执行各个任务的应用场景。

定时器Timer

[Q&A] TimerScheduleThreadPoolExecutor区别

TimerScheduleThreadPoolExecutor
指定绝对时间可以用相对时间
对系统时钟的变化敏感不是
单线程使用线程池。可以配置任意数量的线程
抛出运行时异常会杀死一个线程从而导致Timer死机可以捕获运行时异常且处理它们。
抛出异常的任务将被取消其他任务将继续运行

自定义线程池 ThreadPoolExecutor

# 自定义线程池
ThreadPoolExecutor exec = new ThreadPoolExecutor(3, 5, 50, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(20));

[Q&A]自定义线程好处?
1、 避免了上面的 OOM 问题 ( 自定义线程池 使用 有界队列 ,控制 maximumPoolSize 数量 )
2、 实际使用中可以根据自己机器的性能、业务场景来手动配置线程池的参数。比如核心线程数、使用的任务队列、饱和策略等等
3、 我们可以显示地给我们的线程池命名,这样有助于我们定位问题

[Q&A] 线程池好的实践方案?
1、自定义线程池,使用 ThreadPoolExecutor的构造函数声明线程池
2、给线程池命名和业务挂靠
3、监测线程池运行状态
4、建议不同类别的业务用不同的线程池(尤其杜绝父任务和子任务用同一个线程池)

-----------------------------------------------------------------------------读书笔记摘自 书名:Java并发编程的艺术 作者:方腾飞;魏鹏;程晓明

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值