关于JAVA线程池关键参数,拒绝策略,调度方式

     在实际的使用以及面试中时常碰到关于线程池的问题,但是线程池作为Java程序开发中的基础组件
拥有相当重要的地位,因此结合源码以及代码实验对线程池进行了探究,并用文字记录下来。

如有错误,不妥之处请各位大佬指出

线程池的核心参数

参数 类型 含义

corePoolSize
int
核心线程数

maximumPoolSize
int
最大并行线程数

keepAliveTime
long
非核心线程最大存活时间

unit
TimeUnit
描述存活时间的单位

workQueue
BlockingQueue
存放任务阻塞队列

threadFactory
ThreadFactory
线程工厂

handler
RejectedExecutionHandler
拒绝策略

corePoolSize: 线程池中的核心线程数,规定的是线程池中的常驻线程worker 的数量
maximumPoolSize:线程池的线程最大并行数量,规定的是线程池允许的最大的并行线程数量,在核心线程worker 已满 且 队列已满的情况下,会启动非核心的 线程worker 来执行任务
workQueue:核心执行线程已满时用于存放任务的阻塞队列,推荐使用带有边界的ArrayBlockingQueue

线程池最基本的运行单元是线程池中的一个内部内,Worker :

ThreadPoolExecutor extends AbstractExecutorService {

private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
// java.lang.Integer@Native public static final int SIZE = 32;
// 可见 Integer 是4个byte的长度, 使用了3位来标识线程池的状态,其余位数表示线程池
// 当前的worker的数量
private static final int COUNT_BITS = Integer.SIZE - 3;
// 线程池允许的最大容量,注意 是理论上可以容纳的最大的worker数量,
// 应该没有大佬会
private static final int CAPACITY = (1 << COUNT_BITS) - 1;
// 线程池状态标识
private static final int RUNNING = -1 << COUNT_BITS;
private static final int SHUTDOWN = 0 << COUNT_BITS;
private static final int STOP = 1 << COUNT_BITS;
private static final int TIDYING = 2 << COUNT_BITS;
private static final int TERMINATED = 3 << COUNT_BITS;
//------------------------------------------------------------
// 获取线程池当前状态
private static int runStateOf(int c) { return c & ~CAPACITY; }
// 获取线程池当前 worker 数量
private static int workerCountOf(int c) { return c & CAPACITY; }
// 通过位运算获得 线程池状态标识 + 线程池数量的 结果
private static int ctlOf(int rs, int wc) { return rs | wc; }

/*
因为继承了 AbstractQueuedSynchronizer,可知: worker 通过 cas的方式实现了线程安全
即 当我在接客的时候 不要往我的房间再塞人
*/
Worker extends AbstractQueuedSynchronizer implements Runnable {
// worker会从 ThreadFactory中获得一个线程对象
public void run() {
// 运行线程
runWorker(this);
}
// ... 其他方法是 创建线程对象,aqs方式对创建的线程进行运行,阻塞,中断等行为的方法
}

final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
while (task != null || (task = getTask()) != null) {
w.lock();
try {
// 线程池增强方法,加入线程池的前置操作,线程池监控常用
beforeExecute(wt, task);
Throwable thrown = null;
try {
/**
调用 runable中的run(),执行业务代码块
**/
task.run();
} catch (RuntimeException x) {
...
} finally {
// 线程池增强方法,完成任务之后的后置操作,线程池监控常用
afterExecute(task, thrown);
}
} finally {
task = null;
w.completedTasks++;
w.unlock();
}
}
completedAbruptly = false;
} finally {
// 记录执行结果,并将Worker移除在执行Set集合
processWorkerExit(w, completedAbruptly);
}
}

}

线程池调度方式

线程池的调度,我主要是指线程池当进入一个新任务时是如何完成整个生命周期的,

新的任务进入 =>
先查询核心worker数是否已满 ? 未满则新增核心worker执行任务 ,
已满则查看阻塞队列,阻塞队列未满则加入阻塞队列,
已满 且 查看最大并行线程数是否已满,
已满则调用拒绝策略,拒绝接受新增任务
未满则新增非核心worker处理该任务

也就是说,在核心线程数以及队列容量没有用完之前,设置的最大线程数是无意义的,线程池不会以最大线程数来并行任务。
同时,当我们设置阻塞队列的时候 如果采用 阻塞队列时如果 采用无边界的队列,或者不设置边界,在极端情况下对应用是危险的,会因为 Task的堆积发生OOM,这也是阿里大佬在小本本上要求自己去实现ThreadLocalPool 而不使用Executors中提供的线程池的原因。

线程池中的拒绝策略
实现自己的线程池拒绝策略就是这个接口,在线程池已满的情况下,我们可以把任务放进MQ,Redis,
应用内部队列中保存起来,找特定的时间窗口再去执行,当然,具体情况具体分析,反正接口,他就在那里

public interface RejectedExecutionHandler {
void rejectedExecution(Runnable r, ThreadPoolExecutor executor);
}

JDK大佬提供的拒绝策略:
AbortPolicy(默认):直接报错
DiscardPolicy:不报错,悄悄的就丢了,注意是悄悄的,什么反应都没有
DiscardOldestPolicy:不报错,悄悄的把队列中等得最久得丢了
CallerRunsPolicy:调用者自己处理

使用线程池的注意事项

1,注意初始化线程池时确定合理的并行数
2,不要使用没有边界的队列
3,拒绝策略需结合业务需求慎重选择,当然如果项目规模不大,且并发量低请忽略,默认即可,因为根本走不到那一步,但是咱不能不知道
4,码字不易,如果您老吃得好,欢迎再来,如果要端回家,麻烦给打个标,注明本店位置,下次再见

原创:https://www.panoramacn.com
源码网提供WordPress源码,帝国CMS源码discuz源码,微信小程序,小说源码,杰奇源码,thinkphp源码,ecshop模板源码,微擎模板源码,dede源码,织梦源码等。

专业搭建小说网站,小说程序,杰奇系列,微信小说系列,app系列小说

关于JAVA线程池关键参数,拒绝策略,调度方式

免责声明,若由于商用引起版权纠纷,一切责任均由使用者承担。

您必须遵守我们的协议,如果您下载了该资源行为将被视为对《免责声明》全部内容的认可-> 联系客服 投诉资源
www.panoramacn.com资源全部来自互联网收集,仅供用于学习和交流,请勿用于商业用途。如有侵权、不妥之处,请联系站长并出示版权证明以便删除。 敬请谅解! 侵权删帖/违法举报/投稿等事物联系邮箱:2640602276@qq.com
未经允许不得转载:书荒源码源码网每日更新网站源码模板! » 关于JAVA线程池关键参数,拒绝策略,调度方式
关注我们小说电影免费看
关注我们,获取更多的全网素材资源,有趣有料!
120000+人已关注
分享到:
赞(0) 打赏

评论抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

您的打赏就是我分享的动力!

支付宝扫一扫打赏

微信扫一扫打赏