java线程池中线程数量到底是几

 更新时间:2022年08月01日 11:21:42   作者:Java个体户  
本文主要介绍了java线程池中线程数量到底是几,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

线程池配置

线程池配置,假设是:

1.最小数量是5

2.阻塞队列容量是10

3.最大数量是20

线程池里的业务线程数量小于最小数量(5)

第一个请求

第一个请求进来的时候,这个时候,线程池没有线程,就创建新的工作线程(即Worker线程)。

然后,这个工作线程去处理当前请求的业务线程。

第二个请求

第二个请求进来的时候,这个时候,线程池已经有了一个工作线程。

但是,要注意,这个时候是不会复用线程池里已有的工作线程的。而是创建新的工作线程。

因为,线程池里根本没有复用线程的概念。

说白了,无论线程池里已有的这个工作线程是否在处理业务线程,即不管它空闲与否,其实都会创建新的工作线程。

第三个请求

同上,仍然创建新的工作线程。

。。。

第五个请求

同上。仍然创建新的工作线程。

注意,现在,线程池有几个工作线程?5个。

即,每个请求进来,都创建一个新的工作线程。

小于阻塞队列容量(10)

第六个请求

第六个请求进来的时候,提交到阻塞队列。

然后,再慢慢消费。

具体来说,是由线程池里的工作线程来慢慢消费。

具体消费的源码,参考:复用线程小节。

第七个请求

同上,也是先添加到阻塞队列。

。。。

第15个请求

同上,也是先添加到阻塞队列。

小于最大数量(20)

第16个请求

先来看,正常情况下,阻塞队列还没塞满(生产环境的容量一般是1000),就会被快速处理掉。

然后,当新的请求进来的时候,继续丢到阻塞队列里面去。

这个是和上面讲的一样。

但是,我们为了方便理解,现在假设之前的15个请求是同时到达,即

  • 前面5个请求

创建5个新的请求。

  • 后面10个请求

全部丢到阻塞队列。

这个时候,阻塞队列已经满了。接着,第16个请求进来了,怎么办?

继续创建新的工作线程。

。。。

第35个请求

同上,继续创建新的工作线程。

注意,这个时候,线程池里的工作线程的数量是多少?20。

因为

  • 前面5个请求,创建了5个新的工作线程。
  • 最后面的15个请求(第16到第35),创建了15个新的工作线程。

所以,总共,创建了20个新的工作线程。线程池,总共有20个工作线程。

拒绝策略

第36个请求

假设前面的请求都没有处理完,这个时候,来了第36个请求,怎么办?

只能采取拒绝策略。

具体采用哪个拒绝策略?比如说,一般情况下,都是采用丢弃。

复用线程

前面说了,线程池里没有复用线程的概念。

那到底是怎么回事呢?既然不能复用线程,那搞个线程池有个几把用?

具体是这样子,虽然,线程池里的工作线程不能被复用,仅仅是指类似数据库连接池里的连接的那种复用,即

  • 用的时候,从连接池取
  • 用完了,归还到连接池

线程池里的对象复用,是基于循环,而不是用完之后再还回去。

什么意思呢?就是工作线程,不断的从阻塞队列里取业务线程,然后执行业务线程。

伪代码

工作线程{
  run(){
    while(){
      1.从阻塞队列,取业务线程
      2.执行业务线程;
    }
  }
}

所以,线程池和连接池的区别在于,线程池的对象是线程,可以不断的循环读业务线程。而连接池的对象,是用完了归还到连接池里去。

jdk源码-java.util.concurrent.ThreadPoolExecutor#runWorker

/**
     * 核心步骤
     * 1.从阻塞队列,读业务线程
     * 2.执行业务线程
     * 
     * ---
     * Main worker run loop.  Repeatedly gets tasks from queue and
     * executes them, while coping with a number of issues:
     *
     * 1. We may start out with an initial task, in which case we
     * don't need to get the first one. Otherwise, as long as pool is
     * running, we get tasks from getTask. If it returns null then the
     * worker exits due to changed pool state or configuration
     * parameters.  Other exits result from exception throws in
     * external code, in which case completedAbruptly holds, which
     * usually leads processWorkerExit to replace this thread.
     *
     * 2. Before running any task, the lock is acquired to prevent
     * other pool interrupts while the task is executing, and then we
     * ensure that unless pool is stopping, this thread does not have
     * its interrupt set.
     *
     * 3. Each task run is preceded by a call to beforeExecute, which
     * might throw an exception, in which case we cause thread to die
     * (breaking loop with completedAbruptly true) without processing
     * the task.
     *
     * 4. Assuming beforeExecute completes normally, we run the task,
     * gathering any of its thrown exceptions to send to afterExecute.
     * We separately handle RuntimeException, Error (both of which the
     * specs guarantee that we trap) and arbitrary Throwables.
     * Because we cannot rethrow Throwables within Runnable.run, we
     * wrap them within Errors on the way out (to the thread's
     * UncaughtExceptionHandler).  Any thrown exception also
     * conservatively causes thread to die.
     *
     * 5. After task.run completes, we call afterExecute, which may
     * also throw an exception, which will also cause thread to
     * die. According to JLS Sec 14.20, this exception is the one that
     * will be in effect even if task.run throws.
     *
     * The net effect of the exception mechanics is that afterExecute
     * and the thread's UncaughtExceptionHandler have as accurate
     * information as we can provide about any problems encountered by
     * user code.
     *
     * @param w the worker
     */
    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();
                // If pool is stopping, ensure thread is interrupted;
                // if not, ensure thread is not interrupted.  This
                // requires a recheck in second case to deal with
                // shutdownNow race while clearing interrupt
                if ((runStateAtLeast(ctl.get(), STOP) ||
                     (Thread.interrupted() &&
                      runStateAtLeast(ctl.get(), STOP))) &&
                    !wt.isInterrupted())
                    wt.interrupt();
                try {
                    beforeExecute(wt, task);
                    Throwable thrown = null;
                    try {
                        //执行业务线程
                        task.run();
                    } catch (RuntimeException x) {
                        thrown = x; throw x;
                    } catch (Error x) {
                        thrown = x; throw x;
                    } catch (Throwable x) {
                        thrown = x; throw new Error(x);
                    } finally {
                        afterExecute(task, thrown);
                    }
                } finally {
                    task = null;
                    w.completedTasks++;
                    w.unlock();
                }
            }
            completedAbruptly = false;
        } finally {
            processWorkerExit(w, completedAbruptly);
        }
    }

到此这篇关于java线程池中线程数量到底是几的文章就介绍到这了,更多相关java 线程数量内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • java Zookeeper简述

    java Zookeeper简述

    ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件。下面通过本文给大家分享java 中 zookeeper简单使用,需要的朋友参考下吧
    2021-09-09
  • Spring Cloud出现Options Forbidden 403问题解决方法

    Spring Cloud出现Options Forbidden 403问题解决方法

    本篇文章主要介绍了Spring Cloud出现Options Forbidden 403问题解决方法,具有一定的参考价值,有兴趣的可以了解一下
    2017-11-11
  • Java调用Python代码的几种方法小结

    Java调用Python代码的几种方法小结

    Python语言有丰富的系统管理、数据处理、统计类软件包,因此从java应用中调用Python代码的需求很常见、实用,本文介绍几种方法从java调用Python代码,从而最大化利用两个语言的优势,需要的朋友可以参考下
    2025-01-01
  • Java @Transactional指定回滚条件

    Java @Transactional指定回滚条件

    这篇文章主要介绍了Java @Transactional指定回滚条件,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的朋友可以参考一下
    2022-08-08
  • Spring Shell打Jar包时常用小技巧

    Spring Shell打Jar包时常用小技巧

    这篇文章主要介绍了Spring Shell打Jar包时常用小技巧,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-10-10
  • SpringBoot实现服务接入nacos注册中心流程详解

    SpringBoot实现服务接入nacos注册中心流程详解

    这篇文章主要介绍了SpringBoot实现服务接入nacos注册中心流程,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧
    2023-01-01
  • Java中的snowflake算法详解

    Java中的snowflake算法详解

    这篇文章主要介绍了Java中的snowflake算法详解,Snowflake算法产生是为了满足Twitter每秒上万条消息的请求,每条消息都必须分配一条唯一的id,这些id还需要一些大致的顺序,并且在分布式系统中不同机器产生的id必须不同,需要的朋友可以参考下
    2023-08-08
  • 解决无法解析javax.servlet的方法

    解决无法解析javax.servlet的方法

    最近在创建一个servlet时,自动生成的代码中出现servlet无法解析的提示,令我无法正常使用servlet里的方法,在对各个步骤进行查看后,发现了问题所在,需要的朋友可以参考下
    2021-05-05
  • SpringBoot基于数据库实现定时任务过程解析

    SpringBoot基于数据库实现定时任务过程解析

    这篇文章主要介绍了SpringBoot基于数据库实现定时任务过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-12-12
  • Springboot项目中定时任务的四种实现方式详解

    Springboot项目中定时任务的四种实现方式详解

    Spring的@Scheduled注解是一种非常简单和便捷的实现定时任务的方式,通过在方法上添加@Scheduled注解,我们可以指定方法在特定的时间间隔或固定的时间点执行,本文给大家介绍Springboot项目中定时任务的四种实现方式,感兴趣的的朋友一起看看b
    2024-02-02

最新评论