java的线程池是怎么实现的?

194 阅读5分钟

java的线程池是怎么实现的?

java的线程都有哪些状态?

【图解】透彻Java线程状态转换_Java知音_的博客-CSDN博客

java的线程池是怎么实现的?

线程池在内部实际上构建了一个生产者消费者模型,将线程和任务两者解耦,并不直接关联,从而良好的缓冲任务,复用线程。

任务管理部分充当生产者的角色,当任务提交后,线程池会判断该任务后续的流转:

(1)直接申请线程执行该任务;

(2)缓冲到队列中等待线程执行;

(3)拒绝该任务。

线程管理部分是消费者,它们被统一维护在线程池内,根据任务请求进行线程的分配,当线程执行完任务后则会继续获取新的任务去执行,最终当线程获取不到任务的时候,线程就会被回收。

worker线程队列.

workQueue任务管理.

java.util.concurrent.ThreadPoolExecutor

private final BlockingQueue<Runnable> workQueue;

private final HashSet<Worker> workers = new HashSet<Worker>();

线程池需要解决的问题

  1. 线程池如何维护自身的状态,用于让使用者知道线程池内部的运行状态?

  2. 线程池如何管理任务?

    1. 什么时候可以提交任务?

    2. 任务满了怎么处理?

  3. 要如何管理线程?

    1. 如何知道这个线程已执行完,执行中,

    2. 什么时候可以销毁,什么时候可以复用?

线程池如何维护自身状态?

线程池运行的状态,并不是用户显式设置的,而是伴随着线程池的运行,由内部来维护。线程池内部使用一个变量维护两个值:运行状态(runState)和线程数量 (workerCount)。在具体实现中,线程池将运行状态(runState)、线程数量 (workerCount)两个关键参数的维护放在了一起,如下代码所示:

private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));

Worker线程是怎么管理的?

线程池为了掌握线程的状态并维护线程的生命周期,设计了线程池内的工作线程Worker。

Worker线程是怎么执行任务的?

  1. while循环不断地通过getTask()方法获取任务。
  2. getTask()方法从阻塞队列中取任务。
  3. 如果线程池正在停止,那么要保证当前线程是中断状态,否则要保证当前线程不是中断状态。
  4. 执行任务。
  5. 如果getTask结果为null则跳出循环,执行processWorkerExit()方法,销毁线程。

线程池是怎么创建线程的?

查看源代码可以看到 在addWorker方法里

使用的Executors.defaultThreadFactory()#newThread创建出来的线程.



private boolean addWorker(Runnable firstTask, boolean core){

// ...中间省略

Worker w = null;

try {

    w = new Worker(firstTask);

    final Thread t = w.thread;

}





Worker(Runnable firstTask) {

    setState(-1); // inhibit interrupts until runWorker

 this.firstTask = firstTask;

    this.thread = getThreadFactory().newThread(this);

}



his(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,

     Executors.defaultThreadFactory(), defaultHandler);

一个线程池中的线程异常了,那么线程池会怎么处理这个线程?

  1. 怎么处理这个线程?

当一个线程异常了,processWorkerExit方法会把这个线程从线程池中移除.,会重新addWorker一个新的线程.

  1. 会对其它线程有影响吗?

不会影响.

  1. 异常堆栈会输出吗?
  • 当执行方式是execute时,可以看到堆栈异常的输出

  • 当执行方式是submit时,堆栈异常没有输出。但是调用Future.get()方法时,可以捕获到异常

线程池被创建后里面有线程吗?如果没有的话,你知道有什么方法对线程池进行预热吗?

线程池可以动态调整参数吗?

线程池的大小可以动态调整,具体参见文档.

线程池的监控

线程池怎么实现监控?

用户基于JDK原生线程池ThreadPoolExecutor提供的几个public的getter方法,可以读取到当前线程池的运行状态以及参数

线程池监控有哪些维度?

线程池活跃度、

任务的执行Transaction(频率、耗时)

Reject异常

线程池内部统计信息等等

怎么实现线程池的监控?

  1. 统一标准 以及 agent采集,根据实际情况采集需要的数据进行监控以及动态调整。

  2. 简易版,启动一个线程定期采集相关的监控数据.

Spring中使用的线程池?

spring的线程池ThreadPoolTaskExecutor 是对java的ThreadPoolExecutor进行了封装处理。

org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor

ThreadPoolTaskExecutor 什么时候内部创建了 ThreadPoolExecutor?

可以注意到也实现了 InitializingBean 接口.

具体初始化实现类

org.springframework.scheduling.concurrent.ExecutorConfigurationSupport



@Override

public void afterPropertiesSet() {

   initialize();

}



 /**

 * Set up the ExecutorService.

 */

public void initialize() {

   if (logger.isInfoEnabled()) {

      logger.info("Initializing ExecutorService" + (this.beanName != null ? " '" + this.beanName + "'" : ""));

   }

   if (!this.threadNamePrefixSet && this.beanName != null) {

      setThreadNamePrefix(this.beanName + "-");

   }

   this.executor = initializeExecutor(this.threadFactory, this.rejectedExecutionHandler);

}



 /**

 * Create the target {@link java.util.concurrent.ExecutorService} instance.

 * Called by {@code afterPropertiesSet}.

 * @param threadFactory the ThreadFactory to use

 * @param rejectedExecutionHandler the RejectedExecutionHandler to use

 * @return a new ExecutorService instance

 * @see #afterPropertiesSet()

 */

protected abstract ExecutorService initializeExecutor(

      ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler);

在ThreadPoolTaskExecutor 实现并创建了 ThreadPoolExecutor



protected ExecutorService initializeExecutor(

      ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {



   BlockingQueue<Runnable> queue = createQueue(this.queueCapacity);



   ThreadPoolExecutor executor;

   if (this.taskDecorator != null) {

      executor = new ThreadPoolExecutor(

            this.corePoolSize, this.maxPoolSize, this.keepAliveSeconds, TimeUnit.SECONDS,

            queue, threadFactory, rejectedExecutionHandler) {

         @Override

         public void execute(Runnable command) {

            Runnable decorated = taskDecorator.decorate(command);

            if (decorated != command) {

               decoratedTaskMap.put(decorated, command);

            }

            super.execute(decorated);

         }

      };

   }

   else {

      executor = new ThreadPoolExecutor(

            this.corePoolSize, this.maxPoolSize, this.keepAliveSeconds, TimeUnit.SECONDS,

            queue, threadFactory, rejectedExecutionHandler);



   }



   if (this.allowCoreThreadTimeOut) {

      executor.allowCoreThreadTimeOut(true);

   }



   this.threadPoolExecutor = executor;

   return executor;

}

参考文档

Java线程池实现原理及其在美团业务中的实践

一个线程池中的线程异常了,那么线程池会怎么处理这个线程? - 反光的小鱼儿 - 博客园

线程池的参数动态调整 - java金融 - 博客园

blog.csdn.net/f80407515/a…

JAVA系列:Synchronized工作原理_NIO4444的博客-CSDN博客_java synchronized原理