漫谈Java 线程池ThreadPoolExecutor

参考资料
https://www.cnblogs.com/dolphin0520/p/3932921.html
https://www.jianshu.com/p/896b8e18501b

简介

Java线程池的核心类为ThreadPoolExecutor
线程池中的FixedThreadPool、SingleThreadExecutor、CachedThreadPool、ScheduledThreadPool底层均是调用了ThreadPoolExecutor的构造方法初始化的线程池
线程池与连接池的原理类似,省去了频繁的初始化和销毁的步骤,节省了时间,维护着活跃的线程供调用。

##ThreadPoolExecutor构造方法和基本原理

1、ThreadPoolExecutor构造方法

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

通过源码可以看到ThreadPoolExecutor核心的构造方法,下面来分析下具体的参数的含义
corePoolSize ---- 保持在池中的线程数,即使他们是空闲的
maximumPoolSize — 池中允许的最大线程数
keepAliveTime ---- 当线程数大于corePoolSize,多余的空闲线程在终止前等待新任务的最大时间。
unit ---- keepAliveTime 中参数的时间单位
workQueue ---- 任务执行前用于保存任务的队列
threadFactory ---- 执行程序创建新线程时要使用的工厂
handler ---- 由于达到线程边界和队列容量而阻塞执行时使用的处理程序

  • 1、workQueue

workQueue的类型为BlockingQueue,通常可以取下面三种类型:
1)ArrayBlockingQueue:基于数组的先进先出队列,此队列创建时必须指定大小;
2)LinkedBlockingQueue:基于链表的先进先出队列,如果创建时没有指定此队列大小,则默认为Integer.MAX_VALUE;(默认的就是所谓的无界队列,maximumPoolSize因此也就没有了意义)
3)synchronousQueue:这个队列比较特殊,它不会保存提交的任务,而是将直接新建一个线程来执行新来的任务。

2、基本原理

这个样例我是参考的,感觉说的很好
corePoolSize在很多地方被翻译成核心池大小,其实我的理解这个就是线程池的大小。举个简单的例子:
假如有一个工厂,工厂里面有10个工人,每个工人同时只能做一件任务。
因此只要当10个工人中有工人是空闲的,来了任务就分配给空闲的工人做;
当10个工人都有任务在做时,如果还来了任务,就把任务进行排队等待;
如果说新任务数目增长的速度远远大于工人做任务的速度,那么此时工厂主管可能会想补救措施,比如重新招4个临时工人进来;
然后就将任务也分配给这4个临时工人做;
如果说着14个工人做任务的速度还是不够,此时工厂主管可能就要考虑不再接收新的任务或者抛弃前面的一些任务了。
当这14个工人当中有人空闲时,而新任务增长的速度又比较缓慢,工厂主管可能就考虑辞掉4个临时工了,只保持原来的10个工人,毕竟请额外的工人是要花钱的。

这个例子中的corePoolSize就是10,而maximumPoolSize就是14(10+4)。
也就是说corePoolSize就是线程池大小,maximumPoolSize在我看来是线程池的一种补救措施,即任务量突然过大时的一种补救措施。

示例:
ThreadPoolExecutor pool = new ThreadPoolExecutor(2,5,10L, TimeUnit.SECONDS,new ArrayBlockingQueue<>(5));
如下线程池最多能接受10个线程,等待队列里5个,最大线程数5个,多的线程请求将会被拒绝
image.png

简单代码示例

我们这边有个需求,就是从mysql拉取数据写入到HDFS上,因为mysql支持分页,所以我们这边打算就用线程池来做

ThreadPoolExecutor threadPool = new ThreadPoolExecutor(3, 3, 1,
        TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(),
        new ThreadPoolExecutor.DiscardOldestPolicy());
for (int i = 0; i < 3; i++) {
	String sql = "select * from DWA.DWA_DEMO limit " + (i * avg + 1) + "," + (avg);
	System.out.println(sql);
	threadPool.submit(new MysqlRunable(sql,bw));
}
threadPool.shutdown();
while (!threadPool.isTerminated()) {
}

其中threadPool.isTerminated() 是为了等待所有线程执行完毕
我们这边的workQueue选择的是LinkedBlockingQueue无界队列,因为也考虑到队列各自独立而且必须执行。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值