JDK1.8中的线程池

上面这段代码一直在用,面试的时候也经常被问到,却从未深究过,不知道线程池到底是怎么回事,今天看看源代码,一探其究竟

线程池主要控制的状态是ctl,它是一个原子的整数,其包含两个概念字段:

  • workerCount:有效的线程数量
  • runState:线程池的状态

为了在一个整型值里面包含这两个字段,我们限制workerCount最多2的29次方减1

runState的值有这样几种:

  • RUNNING:  接受新的任务,并处理队列中的任务
  • SHUTDOWN:不接受新的任务,继续处理队列中的任务
  • STOP:           不接受新的任务,也不处理队列中的任务,并且中断正在处理的任务
  • TIDYING:      所有任务都结束了,workerCount是0,通过调用terminated()方法转换状态
  • TERMINATED:terminated()方法已经完成

状态之间的转换时这样的:

RUNNING -> SHUTDOWN

  调用shutdown()方法,或者隐式的调用finalize()方法

(RUNNING or SHUTDOWN) -> STOP

  调用shoutdownNow()方法

SHUTDOWN -> TIDYING

  当队列和池都是空的时候

STOP -> TIDYING

  当池是空的时候

TIDYING -> TERMINATED

  当terminated()方法调用完成时

Integer.SIZE=31

Integer.SIZE - 3 = 29

所以,COUNT_BITS = 29

高3位存储runState

接下来看最复杂的那个构造方法

参数详解

  • corePoolSize:保持在池中的线程数(PS:即使它们处于空闲状态)
  • maximumPoolSize:池中允许的最大线程数
  • keepAliveTime:当线程数超过核心线程数的时候,超出的线程的最大生存时间
  • unit:keepAliveTime的单位
  • workQueue:维护待处理的任务的队列
  • threadFactory:创建线程的工厂

1、如果正在运行的线程数少于核心线程数,则新建一个线程去运行这个任务

2、如果工作队列没有满,则放到工作队列中

3、如果工作队列已满(PS:workQueue.offer(command)返回false),则再新建线程

4、若线程数已经达到最大线程数则reject(command)

在前面execute方法中,有3处调用了addWork()方法

第一处,如果当前有效线程数少于核心线程数,则调用之,此时线程数的边界是核心线程数

第二处,如果当前有效线程数超过核心线程数,并且将新任务放到队列中,此时有效线程数是0,则创建一个新线程

第三处,如果当前有效线程数超过核心线程数,并且队列已经放满了,并且有效线程数小于最大线程数,此时调用以创建新线程,

当前的有效线程都在works里面,而works里面放的是Worker对象,接下来看Worker

前一步中,线程的start()方法,线程运行的时候执行run()方法,而Worker继承Runnable并重新run()方法,run()方法又调用外部的runWorker()方法,所以,在线程池中新创建的线程运行时调用的是runWorker()方法

runWorker()方法循环的从队列中取出任务并执行它。也就是说,池中所有的线程都是在创建的时候如果传进来新任务,则先执行新任务,然后循环从队列中取出任务并执行

接下来,看Executors中常见的几种线程池的区别

可以看到

newSingleThreadExecutor:核心线程数和最大线程数都是1,队列是LinkedBlockingQueue

newFixedThreadPool:核心线程数和最大线程数相等,超过核心线程数的空闲线程生存时间是0,队列是LinkedBlockingQueue

newCachedThreadPool:核心线程数是0,最大线程数是Integer.MAX_VALUE,空闲线程生存时间是1min,队列是SynchronousQueue

原文地址:https://www.cnblogs.com/cjsblog/p/8214921.html

时间: 2024-11-10 17:25:18

JDK1.8中的线程池的相关文章

Java中的线程池

综述 在我们的开发中经常会使用到多线程.例如在Android中,由于主线程的诸多限制,像网络请求等一些耗时的操作我们必须在子线程中运行.我们往往会通过new Thread来开启一个子线程,待子线程操作完成以后通过Handler切换到主线程中运行.这么以来我们无法管理我们所创建的子线程,并且无限制的创建子线程,它们相互之间竞争,很有可能由于占用过多资源而导致死机或者OOM.所以在Java中为我们提供了线程池来管理我们所创建的线程. 线程池的使用 采用线程池的好处 在这里我们首先来说一下采用线程池的

《Java并发编程的艺术》 第9章 Java中的线程池

第9章 Java中的线程池 在开发过程中,合理地使用线程池能带来3个好处: 降低资源消耗.通过重复利用已创建的线程 降低线程创建和销毁造成的消耗. 提高响应速度.当任务到达时,任务可以不需要等到线程创建就能立即执行. 提高线程的可管理性.线程是稀缺资源,如果无限制地创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一分配.调优和监控. 9.1 线程池的实现原理 当提交一个新任务到线程池时,线程池的处理流程如下: 1)线程池判断核心线程池里的线程是否都在执行任务.如果不是,则创建

Android中的线程池

总会有线程,总会有队列,等着被执行吧.so,让我们再深深看看线程池: 简介: 线程的使用在java中占有极其重要的地位,在jdk1.4极其之前的jdk版本中,关于线程池的使用是极其简陋的.在jdk1.5之后这一情况有了很大的改观.Jdk1.5之后加入了java.util.concurrent包,这个包中主要介绍java中线程以及线程池的使用.为我们在开发中处理线程的问题提供了非常大的帮助. 作用: 线程池作用就是限制系统中执行线程的数量.     根据系统的环境情况,可以自动或手动设置线程数量,

从源代码分析Universal-Image-Loader中的线程池

一般来讲一个网络访问就需要App创建一个线程来执行,但是这也导致了当网络访问比较多的情况下,线程的数目可能积聚增多,虽然Android系统理论上说可以创建无数个线程,但是某一时间段,线程数的急剧增加可能导致系统OOM.在UIL中引入了线程池这种技术来管理线程.合理利用线程池能够带来三个好处.第一:降低资源消耗.通过重复利用已创建的线程降低线程创建和销毁造成的消耗.第二:提高响应速度.当任务到达时,任务可以不需要等到线程创建就能立即执行.第三:提高线程的可管理性.线程是稀缺资源,如果无限制的创建,

Spring中的线程池ThreadPoolTaskExecutor

1.直接调用Spring框架中的ThreadPoolTaskExecutor ThreadPoolTaskExecutor poolTaskExecutor = new ThreadPoolTaskExecutor(); //线程池所使用的缓冲队列 poolTaskExecutor.setQueueCapacity(200); //线程池维护线程的最少数量 poolTaskExecutor.setCorePoolSize(5); //线程池维护线程的最大数量 poolTaskExecutor.s

Tomcat中的线程池StandardThreadExecutor

之所以今天讨论它,因为在motan的的NettyServer中利用它这个线程池可以作为业务线程池,它定制了一个自己的线程池.当然还是基于jdk中的ThreadExecutor中的构造方法和execute方法,然后在外边包装一层. public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue,

理解java中的线程池

1.引入线程池的原因 对于多线程编程,处理每个请求都要创建一个线程,这不仅要花费时间在创建线程的过程中,还会出现创建线程过多未释放导致的系统内存不足,内存溢出问题,因此引入线程池的概念.线程池,就是在一个容器中创建适量的线程,在程序访问的时候直接调用该线程即可访问. 2.类比数据库连接池. 数据库连接池与线程池类似,dao层访问数据库时,首先会,加载驱动,建立连接,而每次频繁的建立连接肯定会大大降低系统运行效率,因此,数据库连接池出现了,下面以一张图进行说明: 如上图,没连接池时访问一次数据库便

IIS与ASP.NET中的线程池

1. W3 Thread Pool(W3TP) 当处于内核模式的http.sys接收到来自用户的请求之后,会将请求放入队列中.那处于用户模式的w3wp进程如何从内核模式的队列中取出请求呢?I/O完成端口(IOCP,I/O Completion Port)闪亮登场.w3wp专门用了一个线程池干这个--W3TP,可以通过process explorer捕捉到它的身影. 2. .NET线程池 当请求被W3TP从http.sys的队列中取出来后,接下来的工作就会转交给ASP.NET,这时另一个线程池粉墨

如何创建Java中的线程池

线程是Java的一大特性,它可以是给定的指令序列.给定的方法中定义的变量或者一些共享数据(类一级的变量).在Java中每个线程有自己的堆栈和程序计数器(PC),其中堆栈是用来跟踪线程的上下文(上下文是当线程执行到某处时,当前的局部变量的值),而程序计数器则用来跟踪当前线程正在执行的指令. 一个线程不能访问另外一个线程的堆栈变量,而且这个线程必须处于如下状态之一: 1.排队状态(Ready),在用户创建了一个线程以后,这个线程不会立即运行.当线程中的方法start()被调用时,这个线程就会进行排队