java并发编程-线程池

文章详细阐述了Java线程池ThreadPoolExecutor的运作机制,包括核心线程与最大线程的管理,任务队列的使用,以及超时和拒绝策略的执行情况。在提交任务时,线程池会根据核心线程数、队列容量和最大线程数来决定是否创建新线程。此外,还介绍了构造函数和execute方法的关键逻辑,以及Worker类和runWorker方法在处理任务执行中的作用。
摘要由CSDN通过智能技术生成

线程池模型

大致的线程池模型如下图所示

  1. 提交任务,如果线程池中的活跃线程数小于核心线程数,则开启新的线程,直到核心线程数满了为止
  2. 如果核心线程用完了,则会放到队列中
  3. 如果队列中放不下了,才会开启新的线程
  4. 线程会自旋,从队列中拉取新的任务
  5. 如果线程在自旋的过程中,发现自己拉取超时了,并且线程数大于核心线程数,则跳出自旋,直接结束自己的线程
  6. 核心线程继续自旋,直至手动结束线程池
    线程池模型

初始化线程池

ThreadPoolExecutor pool = new ThreadPoolExecutor(1,//最小线程数|核心线程数
                2,//最大线程数
                200L,//非核心线程数最大存活时间
                TimeUnit.MICROSECONDS,//时间单位
                new ArrayBlockingQueue<>(200),//队列
                new ThreadPoolExecutor.AbortPolicy());//拒绝策略

点进源码去看,发现构造方法什么事情都没干,只是把传进去的参数赋值给了成员变量
那么看来,核心部分应该是在提交线程的地方了

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.acc = System.getSecurityManager() == null ?
             null :
             AccessController.getContext();
     this.corePoolSize = corePoolSize;
     this.maximumPoolSize = maximumPoolSize;
     this.workQueue = workQueue;
     this.keepAliveTime = unit.toNanos(keepAliveTime);
     this.threadFactory = threadFactory;
     this.handler = handler;
 }

提交线程

提交一个普通线程

pool.execute(new Runnable() {
    @Override
    public void run() {
        System.out.println(123);
    }
});

因为线程池的代码太多,就只列举出来重要的部分
execute方法中

int c = ctl.get();
//如果当前线程的数量小于核心线程的数量,则添加核心线程
if (workerCountOf(c) < corePoolSize) {
     if (addWorker(command, true))
         return;
     c = ctl.get();
 }
 //如果当前线程正在运行,并且入队成功
 if (isRunning(c) && workQueue.offer(command)) {
     int recheck = ctl.get();
     //如果当前线程没有运行,则执行拒绝策略
     if (! isRunning(recheck) && remove(command))
         reject(command);
         //如果工作的线程等于0,则提交一个空的线程到线程池中
     else if (workerCountOf(recheck) == 0)
         addWorker(null, false);
 }
 //如果添加任务失败,执行拒绝策略
 else if (!addWorker(command, false))
            reject(command);

addworker方法

//创建一个worker对象
Worker w = new Worker(firstTask);
//获取worker中的thread,这个thread不是用户添加的,是线程池调用线程工厂创建的
final Thread t = w.thread;
//执行thread的run方法
t.start();

Worker的构造方法
可以看到,用户提交的任务被当成了普通的成员变量了
把自己当成了一个线程,传进newThread中了,所以上边的start方法,其实是执行worker的run方法

Worker(Runnable firstTask) {
    setState(-1); // inhibit interrupts until runWorker
    this.firstTask = firstTask;
    this.thread = getThreadFactory().newThread(this);
}

worker中的run方法

public void run() {
    runWorker(this);
}

runWorker方法
可以看到,其实实际执行的是用户提交的线程中的run方法
因为worker、生成的线程、用户提交的线程,全部都是现成,所以会造成思绪乱,被绕进去的感觉

//空方法,用来给用户拓展用的
beforeExecute(wt, task);
Runnable task = w.firstTask;
task.run();
//当task不为空时,就一直循环,当为空时,就跳出循环
while (task != null || (task = getTask()) != null)
//空方法,用来给用户拓展用的
afterExecute(task, thrown);

getTask方法
可以看到,如果设置了线程最大存活时间,则使用线程最大存活时间去拉取,否则,直接阻塞拉取

Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值