服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Java教程 - 你能说下线程池有几个参数吗,分别代表什么?

你能说下线程池有几个参数吗,分别代表什么?

2024-03-12 20:24码农本农 Java教程

task是worker对象封装的任务。如果当前worker对象上没有任务就调用getTask去阻塞队列拿任务,如果能拿到就处理任务。如果getTask返回null就跳出循环,进入processWorkerExit方法。

关于线程池的问题,大多数面试官会问线程池的几个参数的含义,今天就直接聊一聊线程池ThreadPoolExecutor。

先说下线程池中几个参数的含义:

ThreadPoolExecutor初始化的时候一般会有7个参数:

  • corePoolSize:核心线程数
  • maximumPoolSize:最大线程数
  • keepAliveTime:非核心线程保活时间
  • unit:单位
  • workQueue:队列
  • Executors.defaultThreadFactory():线程工场
  • 拒绝策略

ThreadPoolExecutor的工作原理:

往线程池中提交第一个任务,底层会创建第一个核心线程,将线程和任务封装为一个woker对象放入set集合中,接下来每提交一个的任务都会对应创建一个核心线程和这个任务封装的woker对象放入set集合中,直到核心线程数达到corePoolSize,再次提交到线程池的任务会被放到阻塞队列排队执行,如果放队列的过程中,队列满了,就会创建一个非核心线程和这个任务封装为woker对象放入set集合中,如果最终已经达到最大线程数maximumPoolSize,就采用拒绝策略。如果放入队列过程中发现工作线程数位0,则创建一个空任务的Worker。

再来看下线程池的标识:

线程池的标识有两层含义:

  • 一个含义是当前线程池中的线程数量;
  • 一个含义是当前线程池的状态;

底层是用按位分隔的设计方式将一个int类型的变量的32位进行分割,用高3位表示线程状态,低29位表示线程数量。

线程池的5个状态:RUNNING= -1,正常运行状态 SHUTDOWN= 0, 表示不接受新任务,只把队列中的任务处理完结束。STOP= 1,表示不接受新任务,也不处理队列中的任务了。IDYING= 2,非正常状态 TERMINATED = 3,死亡状态

按位分割的好处就是用一个变量表示两个状态,在修改的时候可以利用cas保证原子性。

Worker对象创建逻辑是由addWorker方法实现的。

addWorker方法逻辑:

1.retry;双层循环

第一层循环主要判断:如果当前线程池状态为RUNNING就放行, 如果状态为SHUTDOWN就必须满足传进来的新任务为null,队列中有待处理的任务才会放行(因为SHUTDOWN状态下不接受新任务,只处理队列中的任务);如果状态为STOP,IDYING,TERMINATED就一定不放行;

第二层循环主要是判断线程数,如果是创建核心线程,就判断是否达到corePoolSize,否则就判断是否达到maximumPoolSize,如果达到就返回fasle不放行。

如果未达到就放行,放行的时候会利用cas更新线程数,如果更新成功则两层循环结束,继续下面的逻辑。

因为是cas操作,多线程的情况下可能会有更新线程数量失败的情况,在这种情况下要判断之前获取的线程池状态和现在的线程池状态是否一致,如果不一致那就要重新判断状态,从而进入到外层循环的下一轮循环,如果一致就只需要进入到内层循环的下一轮循环。

2.创建Worker对象

接下来就是创建Worker(任务),Worker类继承aqs,封装了线程工厂,初始化的时候会利用工厂创建一个线程,并且和传进来的任务封装为worker对象。

获取线程池全局锁(reentrylock作为线程池全局锁),进行上锁操作

将创建的worker加入workers集合,workers是一个hashset集合。

放入集合后就可以解锁了

worker创建完成了,接下来就是启动线程,启动线程后就会执行worker中的run方法

3.run方法流程

这个方法中主要的逻辑是这段代码

while (task != null || (task = getTask()) != null){
  逻辑
}

task是worker对象封装的任务。如果当前worker对象上没有任务就调用getTask去阻塞队列拿任务,如果能拿到就处理任务。如果getTask返回null就跳出循环,进入processWorkerExit方法。

我们知道线程池中的任务是放在队列中的,ThreadPoolExecutor中的队列一般默认是阻塞队列LinkedBlockingQueue,

getTask()方法会在这个队列中拿任务,如果有任务就直接返回任务,如果此时队列中无任务,当前线程会阻塞等待任务到来。

但是如果设置了非核心线程最大空闲时间keepAliveTime,代表非核心线程的worker对象中的线程在拿任务的时候不会用take方法,而是用poll,poll这个方法可以设置阻塞等待时间为keepAliveTime。当超过这个时间还没有任务就会返回null。

4.processWorkerExit方法逻辑

上一步中如果没有获取到任务并且返回了null就会进入processWorkerExit方法。这个方法的逻辑就是把当前非核心线程的worker从workers集合中移除。最后会做一个判断:如果此时没有任何工作线程了,并且阻塞队列中还有任务,那就再创建一个不带任务的非核心线程worker。保证有线程去处理队列中的任务。

拒绝策略:

  • AbortPolicy(默认):丢弃任务并抛出 RejectedExecutionException 异常。
  • CallerRunsPolicy:由调用线程处理该任务。
  • DiscardPolicy:丢弃任务,但是不抛出异常。可以配合这种模式进行自定义的处理方式。
  • DiscardOldestPolicy:丢弃队列最早的未处理任务,然后重新尝试执行任务。

其他了解:

线程监控API:
 while (true) {
 System.out.println();
 int queueSize = tpe.getQueue().size();
 System.out.println("当前排队线程数:" + queueSize);
 int activeCount = tpe.getActiveCount();
 System.out.println("当前活动线程数:" + activeCount);
 long completedTaskCount = tpe.getCompletedTaskCount();
 System.out.println("执行完成线程数:" + completedTaskCount);
 long taskCount = tpe.getTaskCount();
 System.out.println("总线程数:" + taskCount);
 Thread.sleep(3000);
 }


原文地址:https://mp.weixin.qq.com/s/ivZk3aMY7OmGP0ROpr15qQ

延伸 · 阅读

精彩推荐
  • Java教程java多线程模拟交通灯管理系统

    java多线程模拟交通灯管理系统

    这篇文章主要为大家详细介绍了java多线程模拟交通灯管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    Lukegwo8692021-11-19
  • Java教程Java显式锁详情

    Java显式锁详情

    这篇文章主要详细的介绍了shenJava显式锁常用的api及标准用法,感兴趣的朋友,需要的朋友可以参考下面文章里的内容...

    IT王小二10122021-12-15
  • Java教程Spring Security使用中Preflight请求和跨域问题详解

    Spring Security使用中Preflight请求和跨域问题详解

    这篇文章主要给大家介绍了关于Spring Security使用中Preflight请求和跨域问题的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定...

    NULL11882021-02-20
  • Java教程在Mac OS上安装Java以及配置环境变量的基本方法

    在Mac OS上安装Java以及配置环境变量的基本方法

    这篇文章主要介绍了在Mac OS上安装Java以及配置环境变量的基本方法,包括查看所安装Java版本的方法,需要的朋友可以参考下 ...

    ISH_ICODE4322020-01-09
  • Java教程使用springboot整合websocket实现群聊教程

    使用springboot整合websocket实现群聊教程

    websocket怎么说呢,就是服务器可以主动向客户端发起对话,下面就是springboot整合websocket实现群聊的操作代码,一起来看一下get新技能吧...

    是南巷的花猫啊9662021-11-24
  • Java教程Java Arrays.sort()用法详解

    Java Arrays.sort()用法详解

    这篇文章主要介绍了Java Arrays.sort()用法详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下...

    barry_gfw10622021-11-18
  • Java教程IDEA连接postgressql数据库操作

    IDEA连接postgressql数据库操作

    这篇文章主要介绍了IDEA连接postgressql数据库操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...

    Zartillery5232020-08-28
  • Java教程java8 Instant 时间及转换操作

    java8 Instant 时间及转换操作

    这篇文章主要介绍了java8 Instant 时间及转换操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...

    stay hungry,stay you12772020-09-17