简述四种线程池(线程池使用及优势)

2025-10-02 00:00:01 :0

简述四种线程池(线程池使用及优势)

今天给各位分享线程池使用及优势的知识,其中也会对线程池使用及优势进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!

本文目录

线程池使用及优势

线程池的主要工作是控制运行的线程数量,处理过程中将任务放入队列,然后在线程创建后启动这些任务,如果线程数超过了最大数量,超出数量的线程就需要排队等候,等待其他线程执行完毕

它的主要特点可以总结为: 线程复用 , 控制最大并发数 , 管理线程

线程池主要优势又如下三点:

Java中的线程池使通过 Executor 框架实现的,使用线程池用到了 Executor , Executors , ExecutorService , ThreadPoolExecutor 这几个类

其中 Executors 是一个工厂方法,提供了快捷创建线程池的方法,常用的线程池又如下几种:

通过查看这三个工厂方法的源码得知:

底层都是创建了 ThreadPoolExecutor 对象,该类的构造方法有7个参数:

线程池的工作流程如下:

当线程池中队列已满且工作线程达到最大数量时,线程池会拒绝新任务的提交直至队列出现空位或有空闲线程,对于拒绝的任务有不同的处理方式,称为拒绝策略。

线程池提供了四种拒绝策略:

以上拒绝策略均实现了 RejectedExecutionHandler 接口

java线程池(一) 简述线程池的几种使用方式

首先说明下java线程是如何实现线程重用的
1. 线程执行完一个Runnable的run()方法后,不会被杀死
2. 当线程被重用时,这个线程会进入新Runnable对象的run()方法12
java线程池由Executors提供的几种静态方法创建线程池。下面通过代码片段简单介绍下线程池的几种实现方式。后续会针对每个实现方式做详细的说明
newFixedThreadPool
创建一个固定大小的线程池
添加的任务达到线程池的容量之后开始加入任务队列开始线程重用总共开启线程个数跟指定容量相同。
@Test
public void newFixedThreadPool() throws Exception {
ExecutorService executorService = Executors.newFixedThreadPool(1);
executorService = Executors.newFixedThreadPool(1, new ThreadFactoryBuilder().build());
RunThread run1 = new RunThread("run 1");
executorService.execute(run1);
executorService.shutdown();
}12345678
newSingleThreadExecutor
仅支持单线程顺序处理任务
@Test
public void newSingleThreadExecutor() throws Exception {
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().build());
executorService.execute(new RunThread("run 1"));
executorService.execute(new RunThread("run 2"));
executorService.shutdown();
}123456789
newCachedThreadPool
这种情况跟第一种的方式类似,不同的是这种情况线程池容量上线是Integer.MAX_VALUE 并且线程池开启缓存60s
@Test
public void newCachedThreadPool() throws Exception {
ExecutorService executorService = Executors.newCachedThreadPool();
executorService = Executors.newCachedThreadPool(new ThreadFactoryBuilder().build());
executorService.execute(new RunThread("run 1"));
executorService.execute(new RunThread("run 2"));
executorService.shutdown();
}123456789
newWorkStealingPool
支持给定的并行级别,并且可以使用多个队列来减少争用。
@Test
public void newWorkStealingPool() throws Exception {
ExecutorService executorService = Executors.newWorkStealingPool();
executorService = Executors.newWorkStealingPool(1);
RunThread run1 = new RunThread("run 1");
executorService.execute(run1);
executorService.shutdown();
}123456789
newScheduledThreadPool
看到的现象和第一种相同,也是在线程池满之前是新建线程,然后开始进入任务队列,进行线程重用
支持定时周期执行任务(还没有看完)
@Test
public void newScheduledThreadPool() throws Exception {
ExecutorService executorService = Executors.newScheduledThreadPool(1);
executorService = Executors.newScheduledThreadPool(1, new ThreadFactoryBuilder().build());
executorService.execute(new RunThread("run 1"));
executorService.execute(new RunThread("run 2"));
executorService.shutdown();
}

创建线程的方式

一、继承Thread类创建线程子类
1.在这子类中重写run方法,在run方法内写线程任务代码
2.创建该子类实例,即是创建了一个线程实例
3.调用该实例的start方法来启动该线程
二、建一个类去实现Runnable接口
1.该类去实现接口的run方法,run方法内写线程任务代码
2.创建该类实例,把该实例当作一个标记target传给Thread类,如:Thread t = new Thread(该类实例);即创建一个线程对象
3.调用线程的star方法来启用该线程

创建线程的6种方式,用Lambda表达式你绝对没用过

继承Thread类,重新run方法

实现Runnable接口,重写run方法

通过实现Callable接口,重写call方法,配合FutureTask,可以得到异步执行的结果。

直接使用 Lambda表达式方式创建多线程,不需要继承或者实现类。(看起来很酷)

提供四种创建线程池的方式:

【Java基础】线程池的原理是什么

什么是线程池?

总归为:池化技术 ---》数据库连接池 缓存架构 缓存池 线程池 内存池,连接池,这种思想演变成缓存架构技术---》 JDK设计思想有千丝万缕的联系

首先我们从最核心的ThreadPoolExecutor类中的方法讲起,然后再讲述它的实现原理,接着给出了它的使用示例,最后讨论了一下如何合理配置线程池的大小。

Java 中的 ThreadPoolExecutor 类

java.uitl.concurrent.ThreadPoolExecutor 类是线程池中最核心的一个类,因此如果要透彻地了解Java 中的线程池,必须先了解这个类。下面我们来看一下 ThreadPoolExecutor 类的具体实现源码。

在 ThreadPoolExecutor 类中提供了四个构造方法:

从上面的代码可以得知,ThreadPoolExecutor 继承了 AbstractExecutorService 类,并提供了四个构造器,事实上,通过观察每个构造器的源码具体实现,发现前面三个构造器都是调用的第四个构造器进行的初始化工作。

下面解释下一下构造器中各个参数的含义:

  • corePoolSize:核心池的大小,这个参数跟后面讲述的线程池的实现原理有非常大的关系。在创建了线程池后,默认情况下,线程池中并没有任何线程,而是等待有任务到来才创建线程去执行任务,除非调用了prestartAllCoreThreads() 或者 prestartCoreThread()方法,从这 2 个方法的名字就可以看出,是预创建线程的意思,即在没有任务到来之前就创建 corePoolSize 个线程或者一个线程。默认情况下,在创建了线程池后,线程池中的线程数为0,当有任务来之后,就会创建一个线程去执行任务,当线程池中的线程数目达到 corePoolSize 后,就会把到达的任务放到缓存队列当中;

  • maximumPoolSize:线程池最大线程数,这个参数也是一个非常重要的参数,它表示在线程池中最多能创建多少个线程;

  • keepAliveTime:表示线程没有任务执行时最多保持多久时间会终止。默认情况下,只有当线程池中的线程数大于 corePoolSize 时,keepAliveTime 才会起作用,直到线程池中的线程数不大于 corePoolSize,即当线程池中的线程数大于 corePoolSize 时,如果一个线程空闲的时间达到 keepAliveTime,则会终止,直到线程池中的线程数不超过 corePoolSize。但是如果调用了 allowCoreThreadTimeOut(boolean) 方法,在线程池中的线程数不大于 corePoolSize 时,keepAliveTime 参数也会起作用,直到线程池中的线程数为0;

  • unit:参数 keepAliveTime 的时间单位,有 7 种取值,在 TimeUnit 类中有 7 种静态属性:

  • workQueue:一个阻塞队列,用来存储等待执行的任务,这个参数的选择也很重要,会对线程池的运行过程产生重大影响,一般来说,这里的阻塞队列有以下几种选择:

ArrayBlockingQueue 和 PriorityBlockingQueue 使用较少,一般使用 LinkedBlockingQueue 和 Synchronous。线程池的排队策略与 BlockingQueue 有关。

  • threadFactory:线程工厂,主要用来创建线程;

  • handler:表示当拒绝处理任务时的策略,有以下四种取值:

具体参数的配置与线程池的关系将在下一节讲述。

从上面给出的 ThreadPoolExecutor 类的代码可以知道,ThreadPoolExecutor 继承了AbstractExecutorService,我们来看一下 AbstractExecutorService 的实现:

AbstractExecutorService 是一个抽象类,它实现了 ExecutorService 接口。

我们接着看 ExecutorService 接口的实现:

而 ExecutorService 又是继承了 Executor 接口,我们看一下 Executor 接口的实现:

多线程实现的四种方式

多线程实现的四种方式Thread裸线程、Executor服务、ForkJoin框架、Actor模型。

1、Thread裸线程

线程是并发最基本的单元。Java线程本质上被映射到操作系统线程,并且每个线程对象对应着一个计算机底层线程。每个线程有自己的栈空间,它占用了JVM进程空间的指定一部分。

线程的接口相当简明,你只需要提供一个Runnable,调用start开始计算。没有现成的API来结束线程,你需要自己来实现。

优点是很接近并发计算的操作系统/硬件模型,并且这个模型非常简单。多个线程运行,通过共享内存通讯。最大劣势是,开发者很容易过分的关注线程的数量。

线程是很昂贵的对象,创建它们需要耗费大量的内存和时间。这是一个矛盾,线程太少,你不能获得良好的并发性;线程太多,将很可能导致内存问题,调度也变得更复杂。如果你需要一个快速和简单的解决方案,你绝对可以使用这个方法,不要犹豫。

2、Executor服务

另一个选择是使用API来管理一组线程。幸运的是,JVM为我们提供了这样的功能,就是Executor接口。它隐藏了如何处理Runnable的细节。

它仅仅说,“开发者!给我任务,我会处理它!”更酷的是,Executors类提供了一组方法,能够创建拥有完善配置的线程池和executor。我们将使用newFixedThreadPool,它创建预定义数量的线程,并且不允许线程数量超过这个预定义值。

这意味着,如果所有的线程都被使用的话,提交的命令将会被放到一个队列中等待;当然这是由executor来管理的。在它的上层,有ExecutorService管理executor的生命周期,以及CompletionService会抽象掉更多细节,作为已完成任务的队列。

如果你需要精确的控制程序产生的线程数量,以及它们的精确行为,那么executor和executor服务将是正确的选择。例如,需要仔细考虑的一个重要问题是,当所有线程都在忙于做其他事情时,需要什么样的策略?

增加线程数量或者不做数量限制?把任务放入到队列等待?如果队列也满了呢?无限制的增加队列大小?

感谢JDK,已经有很多配置项回答了这些问题,并且有着直观的名字,例如上面的
Executors.newFixedThreadPool(4)。

线程和服务的生命周期也可以通过选项来配置,使资源可以在恰当的时间关闭。唯一的不便之处是,对新手来说,配置选项可以更简单和直观一些。然而,在并发编程方面,你几乎找不到更简单的了。总之,对于大型系统,使用executor最合适。

3、ForkJoin框架

通过并行流,使用ForkJoinPool(FJP),Java8中加入了并行流,从此我们有了一个并行处理集合的简单方法。它和lambda一起,构成了并发计算的一个强大工具。

如果你打算运用这种方法,那么有几点需要注意。首先,你必须掌握一些函数编程的概念,它实际上更有优势。其次,你很难知道并行流实际上是否使用了超过一个线程,这要由流的具体实现来决定。如果你无法控制流的数据源,你就无法确定它做了什么。

另外,你需要记住,默认情况下是通过ForkJoinPool.commonPool实现并行的。这个通用池由JVM来管理,并且被JVM进程内的所有线程共享。这简化了配置项,因此你不用担心。

ForkJoin是一个很好的框架,当需要写一个包含并行处理的小型程序时,它是第一选择。它最大的缺点是,你必须预见到它可能产生的并发症。如果对JVM没有整体上的深入了解,这很难做到。这只能来自于经验。

4、Actor模型

JDK中没有actor的实现;因此你必须引用一些实现了actor的库。

简短地说,在actor模型中,你把一切都看做是一个actor。一个actor是一个计算实体,就像上面第一个例子中的线程,它可以从其他actor那里接收消息,因为一切都是actor。

在应答消息时,它可以给其他actor发送消息,或者创建新的actor并与之交互,或者只改变自己的内部状态。相当简单,但这是一个非常强大的概念。生命周期和消息传递由你的框架来管理,你只需要指定计算单元是什么就可以了。

另外,actor模型强调避免全局状态,这会带来很多便利。你可以应用监督策略,例如免费重试,更简单的分布式系统设计,错误容忍度等等。Akka Actors有Java接口,是最流行的JVM Actor库之一。

实际上,它也有Scala接口,并且是Scala目前默认的actor库。Scala曾经在内部实现了actor。不少JVM语言都实现了actor,比如Future。这些说明了Actor模型已经被广泛接受,并被看做是对语言非常有价值的补充。

Akka actor在内部使用ForkJoin框架来处理工作。Actor模型的强大之处来自于Props对象的接口,通过接口我们可以为actor定义特定的选择模式,定制的邮箱地址等。结果系统也是可配置的,只包含了很少的活动件。

这是一个很好的迹象!使用Actor模型的一个劣势是,它要求你避免全局状态,因此你必须小心的设计你的应用程序,而这可能会使项目迁移变得很复杂。同时,它也有不少优点,因此学习一些新的范例和使用新的库是完全值得的。

可以看出Scala非常简单,它的并发线程你无需跟线程啊,锁啊,线程间通信,线程间协同等难题打交道。它把这些都封装起来了。

线程开启的四种方式(异步委托,thread类,线程池,任务)

文章框架
线程开启方式
--1通过异步委托实现线程
----1.1定义线程
----1.2检测委托线程结束,通过while循环,等待句柄,函数回调

--2通过thread类开启线程
----2.1定义线程
----2.2如何传递参数
----2.3线程优先级
----2.4线程控制

--3、通过线程池开启线程

--4、通过任务开启线程
----4.1通过任务或任务工厂
----4.2连续任务
----4.3任务的层次结构
----4.4任务的执行结果

调用线程控制方法.启动:Thread.Start();停止:Thread.Abort();暂停:Thread.Suspend();继续:Thread.Resume();
值得注意的是: 通过 Thread.Abort() 停下来的线程(或自行运行结束的线程),都无法直接通过 Thread.Start() 方法再次启动,必须重新创建一个线程启动。

注意:线程池中的线程都是后台线程,不能修改为前台线程,不能设置优先级

如果一个任务的执行依赖于另一个任务,即任务的执行有先后顺序。此时,我们可以使用连续任务。
task.ContinueWith(ReadNews)表示一个任务task结束后,才开始执行另一个任务。

在一个任务中可以启动子任务,两个任务异步执行。默认情况下,子任务(即由外部任务创建的内部任务)将独立于其父任务执行。使用TaskCreationOptions.AttachedToParent显式指定将任务附加到任务层次结构中的某个父级。
如果父任务执行完了但是子任务没有执行完,则父任务的状态会被设置为WaitingForChildrenToComplete,只有子任务也执行完了,父任务的状态才会变成RunToCompletion。

使用Task的泛型版本,可以返回任务的执行结果。
下面例子中的TaskWithResult的输入为object类型,返回一个元组Tuple《int, int》。
定义调用TaskWithResult的任务时,使用泛型类Task《Tuple《int, int》》,泛型的参数定义了返回类型。通过构造函数,传递TaskWithResult,构造函数的第二个参数定义了TaskWithResult的输入值。
任务完成后,通过Result属性获取任务的结果。

面试题:线程池有几种实现方式,线程池的七大参数有哪些

在Java编码的过程中,我们经常会创建一个线程来提高程序的执行效率,虽然这样实现起来很方便,但是会有一个问题:如果并发的线程数多,并且每个线程都是执行一个时间很短的任务就结束了,这样会造成频繁的创建和销毁线程从而导致降低系统的效率。
那么问题来了,有没有办法可用复用创建好的线程呢,也就是线程执行完一个任务后,不被销毁,继续执行其他的任务?
在Java可以通过线程池来实现这样的效果。
下面从三个方面和大家一起来探讨一下Java线程池相关的内容。
1.Java中的ThreadPoolExecutor类。
2.Java中4种线程池的使用。
3.Java线程池常用参数如何设置。
一、Java中的ThreadPoolExecutor类
A.ThreadPoolExecutor的重要参数
1.corePoolSize:核心线程数
核心线程会一直存活,及时没有任务需要执行。
当线程数小于核心线程数时,即使有线程空闲,线程池也会优先创建新线程处理。
设置allowCoreThreadTimeout=true(默认false)时,核心线程会超时关闭。
2.queueCapacity:任务队列容量(阻塞队列)
当核心线程数达到最大时,新任务会放在队列中排队等待执行。
3.maxPoolSize:最大线程数
当线程数》=corePoolSize,且任务队列已满时。线程池会创建新线程来处理任务。
当线程数=maxPoolSize,且任务队列已满时,线程池会拒绝处理任务而抛出异常。
4.keepAliveTime:线程空闲时间
当线程空闲时间达到keepAliveTime时,线程会退出,直到线程数量=corePoolSize。
如果allowCoreThreadTimeout=true,则会直到线程数量=0。
5.allowCoreThreadTimeout:允许核心线程超时
6.rejectedExecutionHandler:任务拒绝处理器。
B.ThreadPoolExecutor执行过程
1.当线程数小于核心线程数时,创建线程。
2.当线程数大于等于核心线程数,且任务队列未满时,将任务放入任务队列。
3.当线程数大于等于核心线程数,且任务队列已满。(1)若线程数小于最大线程数,创建线程。(2)若线程数等于最大线程数,抛出异常,拒绝任务。
二、Java中4种线程池
Java通过Executors提供四种线程池,分别为:
newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

java如何确定线程池最多线程的大小

new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, milliseconds,runnableTaskQueue, handler);
参数:
corePoolSize(线程池的基本大小):当提交一个任务到线程池时,线程池会创建一个线程来执行任务,即使其他空闲的基本线程能够执行新任务也会创建线程,等到需要执行的任务数大于线程池基本大小时就不再创建。如果调用了线程池的prestartAllCoreThreads方法,线程池会提前创建并启动所有基本线程。
runnableTaskQueue(任务队列):用于保存等待执行的任务的阻塞队列。 可以选择以下几个阻塞队列。
ArrayBlockingQueue:是一个基于数组结构的有界阻塞队列,此队列按 FIFO(先进先出)原则对元素进行排序。
LinkedBlockingQueue:一个基于链表结构的阻塞队列,此队列按FIFO (先进先出) 排序元素,吞吐量通常要高于ArrayBlockingQueue。静态工厂方法Executors.newFixedThreadPool()使用了这个队列。
SynchronousQueue:一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQueue,静态工厂方法Executors.newCachedThreadPool使用了这个队列。
PriorityBlockingQueue:一个具有优先级的无限阻塞队列。
maximumPoolSize(线程池最大大小):线程池允许创建的最大线程数。如果队列满了,并且已创建的线程数小于最大线程数,则线程池会再创建新的线程执行任务。值得注意的是如果使用了无界的任务队列这个参数就没什么效果。
ThreadFactory:用于设置创建线程的工厂,可以通过线程工厂给每个创建出来的线程设置更有意义的名字。
RejectedExecutionHandler(饱和策略):当队列和线程池都满了,说明线程池处于饱和状态,那么必须采取一种策略处理提交的新任务。这个策略默认情况下是AbortPolicy,表示无法处理新任务时抛出异常。以下是JDK1.5提供的四种策略。
AbortPolicy:直接抛出异常。
CallerRunsPolicy:只用调用者所在线程来运行任务。
DiscardOldestPolicy:丢弃队列里最近的一个任务,并执行当前任务。
DiscardPolicy:不处理,丢弃掉。
当然也可以根据应用场景需要来实现RejectedExecutionHandler接口自定义策略。如记录日志或持久化不能处理的任务。
keepAliveTime(线程活动保持时间):线程池的工作线程空闲后,保持存活的时间。所以如果任务很多,并且每个任务执行的时间比较短,可以调大这个时间,提高线程的利用率。
TimeUnit(线程活动保持时间的单位):可选的单位有天(DAYS),小时(HOURS),分钟(MINUTES),毫秒(MILLISECONDS),微秒(MICROSECONDS, 千分之一毫秒)和毫微秒(NANOSECONDS, 千分之一微秒)。

Android线程池ThreadPoolExecutor详解

       传统的多线程是通过继承Thread类及实现Runnable接口来实现的,每次创建及销毁线程都会消耗资源、响应速度慢,且线程缺乏统一管理,容易出现阻塞的情况,针对以上缺点,线程池就出现了。

       线程池是一个创建使用线程并能保存使用过的线程以达到复用的对象,简单的说就是一块缓存了一定数量线程的区域。

       1.复用线程:线程执行完不会立刻退出,继续执行其他线程;
       2.管理线程:统一分配、管理、控制最大并发数;

       1.降低因频繁创建&销毁线程带来的性能开销,复用缓存在线程池中的线程;
       2.提高线程执行效率&响应速度,复用线程:响应速度;管理线程:优化线程执行顺序,避免大量线程抢占资源导致阻塞现象;
       3.提高对线程的管理度;

       线程池的使用也比较简单,流程如下:

       接下来通过源码来介绍一下ThreadPoolExecutor内部实现及工作原理。

       线程池的最终实现类是ThreadPoolExecutor,通过实现可以一步一步的看到,父接口为Executor:

       其他的继承及实现关系就不一一列举了,直接通过以下图来看一下:

       从构造方法开始看:

       通过以上可以看到,在创建ThreadPoolExecutor时,对传入的参数是有要求的:corePoolSize不能小于0;maximumPoolSize需要大于0,且需要大于等于corePoolSize;keepAliveTime大于0;workQueue、threadFactory都不能为null。
       在创建完后就需要执行Runnable了,看以下execute()方法:

       在execute()内部主要执行的逻辑如下:
       分析点1:如果当前线程数未超过核心线程数,则将runnable作为参数执行addWorker(),true表示核心线程,false表示非核心线程;
       分析点2:核心线程满了,如果线程池处于运行状态则往workQueue队列中添加任务,接下来判断是否需要拒绝或者执行addWorker();
       分析点3:以上都不满足时 ,执行addWorker()添加runnable,失败则执行拒绝策略;
        总结一下:线程池对线程创建的管理,流程图如下:

       在执行addWorker时,主要做了以下两件事:
       分析点1:将runnable作为参数创建Worker对象w,然后获取w内部的变量thread;
       分析点2:调用start()来启动thread;
       在addWorker()内部会将runnable作为参数传给Worker,然后从Worker内部读取变量thread,看一下Worker类的实现:

       Worker实现了Runnable接口,在Worker内部,进行了赋值及创建操作,先将execute()时传入的runnable赋值给内部变量firstTask,然后通过ThreadFactory.newThread(this)创建Thread,上面讲到在addWorker内部执行t.start()后,会执行到Worker内部的run()方法,接着会执行runWorker(this),一起看一下:

       前面可以看到,runWorker是执行在子线程内部,主要执行了三件事:
       分析1:获取当前线程,当执行shutdown()时需要将线程interrupt(),接下来从Worker内部取到firstTask,即execute传入的runnable,接下来会执行;
       分析2:while循环,task不空直接执行;否则执行getTask()去获取,不为空直接执行;
       分析3:对有效的task执行run(),由于是在子线程中执行,因此直接run()即可,不需要start();
       前面看到,在while内部有执行getTask(),一起看一下:

       getTask()是从workQueue内部获取接下来需要执行的runnable,内部主要做了两件事:
       分析1:先获取到当前正在执行工作的线程数量wc,通过判断allowCoreThreadTimeOut及wc 》 corePoolSize来确定timed值;
       分析2:通过timed值来决定执行poll()或者take(),如果WorkQueue中有未执行的线程时,两者作用是相同的,立刻返回线程;如果WorkQueue中没有线程时,poll()有超时返回,take()会一直阻塞;如果allowCoreThreadTimeOut为true,则核心线程在超时时间没有使用的话,是需要退出的;wc 》 corePoolSize时,非核心线程在超时时间没有使用的话,是需要退出的;
       allowCoreThreadTimeOut是可以通过以下方式进行设置的:

       如果没有进行设置,那么corePoolSize数量的核心线程会一直存在。
        总结一下:ThreadPoolExecutor内部的核心线程如何确保一直存在,不退出?
       上面分析已经回答了这个问题,每个线程在执行时会执行runWorker(),而在runWorker()内部有while()循环会判断getTask(),在getTask()内部会对当前执行的线程数量及allowCoreThreadTimeOut进行实时判断,如果工作数量大于corePoolSize且workQueue中没有未执行的线程时,会执行poll()超时退出;如果工作数量不大于corePoolSize且workQueue中没有未执行的线程时,会执行take()进行阻塞,确保有corePoolSize数量的线程阻塞在runWorker()内部的while()循环不退出。
       如果需要关闭线程池,需要如何操作呢,看一下shutdown()方法:

       以上可以看到,关闭线程池的原理:a. 遍历线程池中的所有工作线程;b. 逐个调用线程的interrupt()中断线程(注:无法响应中断的任务可能永远无法终止)
       也可调用shutdownNow()来关闭线程池,二者区别:
       shutdown():设置线程池的状态为SHUTDOWN,然后中断所有没有正在执行任务的线程;
       shutdownNow():设置线程池的状态为STOP,然后尝试停止所有的正在执行或暂停任务的线程,并返回等待执行任务的列表;
       使用建议:一般调用shutdown()关闭线程池;若任务不一定要执行完,则调用shutdownNow();
        总结一下:ThreadPoolExecutor在执行execute()及shutdown()时的调用关系,流程图如下:

       线程池可以通过Executors来进行不同类型的创建,具体分为四种不同的类型,如下:

       可缓存线程池:不固定线程数量,且支持最大为Integer.MAX_VALUE的线程数量:

       1、线程数无限制
       2、有空闲线程则复用空闲线程,若无空闲线程则新建线程
       3、一定程度上减少频繁创建/销毁线程,减少系统开销

       固定线程数量的线程池:定长线程池

       1、可控制线程最大并发数(同时执行的线程数)
       2、超出的线程会在队列中等待。

       单线程化的线程池:可以理解为线程数量为1的FixedThreadPool

       1、有且仅有一个工作线程执行任务
       2、所有任务按照指定顺序执行,即遵循队列的入队出队规则

       定时以指定周期循环执行任务

       一般来说,等待队列 BlockingQueue 有: ArrayBlockingQueue 、 LinkedBlockingQueue 与 SynchronousQueue 。
       假设向线程池提交任务时,核心线程都被占用的情况下:
        ArrayBlockingQueue :基于数组的阻塞队列,初始化需要指定固定大小。
       当使用此队列时,向线程池提交任务,会首先加入到等待队列中,当等待队列满了之后,再次提交任务,尝试加入队列就会失败,这时就会检查如果当前线程池中的线程数未达到最大线程,则会新建线程执行新提交的任务。所以最终可能出现后提交的任务先执行,而先提交的任务一直在等待。
        LinkedBlockingQueue :基于链表实现的阻塞队列,初始化可以指定大小,也可以不指定。
       当指定大小后,行为就和 ArrayBlockingQueue一致。而如果未指定大小,则会使用默认的 Integer.MAX_VALUE 作为队列大小。这时候就会出现线程池的最大线程数参数无用,因为无论如何,向线程池提交任务加入等待队列都会成功。最终意味着所有任务都是在核心线程执行。如果核心线程一直被占,那就一直等待。
        SynchronousQueue :无容量的队列。
       使用此队列意味着希望获得最大并发量。因为无论如何,向线程池提交任务,往队列提交任务都会失败。而失败后如果没有空闲的非核心线程,就会检查如果当前线程池中的线程数未达到最大线程,则会新建线程执行新提交的任务。完全没有任何等待,唯一制约它的就是最大线程数的个数。因此一般配合Integer.MAX_VALUE就实现了真正的无等待。
       但是需要注意的是, 进程的内存是存在限制的,而每一个线程都需要分配一定的内存。所以线程并不能无限个。

关于简述四种线程池到此分享完毕,希望能帮助到您。

简述四种线程池(线程池使用及优势)

本文编辑:admin

更多文章:


easyui调用bartendee模板(EXCEL数据库调用BarTender10.1问题)

easyui调用bartendee模板(EXCEL数据库调用BarTender10.1问题)

大家好,easyui调用bartendee模板相信很多的网友都不是很明白,包括EXCEL数据库调用BarTender10.1问题也是一样,不过没有关系,接下来就来为大家分享关于easyui调用bartendee模板和EXCEL数据库调用Ba

2026年7月18日 14:45

matlab sym(大家好!matlab中syms是什么意思)

matlab sym(大家好!matlab中syms是什么意思)

大家好,今天小编来为大家解答以下的问题,关于matlab sym,大家好!matlab中syms是什么意思这个很多人还不知道,现在让我们一起来看看吧!本文目录大家好!matlab中syms是什么意思matlab中syms什么意思MATLAB

2026年3月27日 04:15

technology各种词性(technique与technology的区别)

technology各种词性(technique与technology的区别)

“technology各种词性”相关信息最新大全有哪些,这是大家都非常关心的,接下来就一起看看technology各种词性(technique与technology的区别)!本文目录technique与technology的区别工艺的近义词

2026年3月28日 22:00

facilitate英语怎么读(促成的英语翻译 促成用英语怎么说)

facilitate英语怎么读(促成的英语翻译 促成用英语怎么说)

各位老铁们,大家好,今天由我来为大家分享facilitate英语怎么读,以及促成的英语翻译 促成用英语怎么说的相关问题知识,希望对大家有所帮助。如果可以帮助到大家,还望关注收藏下本站,您的支持是我们最大的动力,谢谢大家了哈,下面我们开始吧!

2026年2月28日 23:30

vue2diff算法(简单几句话,知道什么是回流重绘、vue虚拟dom、diff算法和key)

vue2diff算法(简单几句话,知道什么是回流重绘、vue虚拟dom、diff算法和key)

大家好,vue2diff算法相信很多的网友都不是很明白,包括简单几句话,知道什么是回流重绘、vue虚拟dom、diff算法和key也是一样,不过没有关系,接下来就来为大家分享关于vue2diff算法和简单几句话,知道什么是回流重绘、vue虚

2026年2月26日 10:15

金山表单移除填写入口什么意思(金山表单提交成功能删除吗)

金山表单移除填写入口什么意思(金山表单提交成功能删除吗)

各位老铁们好,相信很多人对金山表单移除填写入口什么意思都不是特别的了解,因此呢,今天就来为大家分享下关于金山表单移除填写入口什么意思以及金山表单提交成功能删除吗的问题知识,还望可以帮助大家,解决大家的一些困惑,下面一起来看看吧!本文目录金山

2025年9月16日 09:00

column在sql是什么意思(sql语句中的information_schema.COLUMNS 是什么意思呢)

column在sql是什么意思(sql语句中的information_schema.COLUMNS 是什么意思呢)

各位老铁们好,相信很多人对column在sql是什么意思都不是特别的了解,因此呢,今天就来为大家分享下关于column在sql是什么意思以及sql语句中的information_schema.COLUMNS 是什么意思呢的问题知识,还望可以

2026年8月17日 16:15

powerpoint模板(如何制作PowerPoint的模板)

powerpoint模板(如何制作PowerPoint的模板)

今天给各位分享如何制作PowerPoint的模板的知识,其中也会对如何制作PowerPoint的模板进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!本文目录如何制作PowerPoint的模板PPT演示文稿设计模板的默认

2025年7月6日 00:15

optimistic怎么读英语(optimistic怎么读)

optimistic怎么读英语(optimistic怎么读)

“optimistic怎么读英语”相关信息最新大全有哪些,这是大家都非常关心的,接下来就一起看看optimistic怎么读英语(optimistic怎么读)!本文目录optimistic怎么读optimistic 这个英语单词怎么读opti

2026年3月8日 11:45

snackbar怎么读英语(快餐店的英文单词是什么)

snackbar怎么读英语(快餐店的英文单词是什么)

“snackbar怎么读英语”相关信息最新大全有哪些,这是大家都非常关心的,接下来就一起看看snackbar怎么读英语(快餐店的英文单词是什么)!本文目录快餐店的英文单词是什么mobile怎么读主食用英文怎么说快餐店的英文单词是什么快餐店:

2026年3月14日 02:00

儿童编程课网课哪个好(少儿编程课应该选择哪家)

儿童编程课网课哪个好(少儿编程课应该选择哪家)

大家好,儿童编程课网课哪个好相信很多的网友都不是很明白,包括少儿编程课应该选择哪家也是一样,不过没有关系,接下来就来为大家分享关于儿童编程课网课哪个好和少儿编程课应该选择哪家的一些知识点,大家可以关注收藏,免得下次来找不到哦,下面我们开始吧

2025年7月11日 01:30

html中生成滚动条或文字(html如何实现滚动文字和音乐)

html中生成滚动条或文字(html如何实现滚动文字和音乐)

大家好,html中生成滚动条或文字相信很多的网友都不是很明白,包括html如何实现滚动文字和音乐也是一样,不过没有关系,接下来就来为大家分享关于html中生成滚动条或文字和html如何实现滚动文字和音乐的一些知识点,大家可以关注收藏,免得下

2026年2月25日 20:45

js开发动态星星(使用Canvas绘制星星闪烁的效果)

js开发动态星星(使用Canvas绘制星星闪烁的效果)

本篇文章给大家谈谈js开发动态星星,以及使用Canvas绘制星星闪烁的效果对应的知识点,希望对各位有所帮助,不要忘了收藏本站喔。本文目录使用Canvas绘制星星闪烁的效果通过JS实现分数对应的星星评分体现QQ空间模块带星星的代码js星星评价

2026年3月27日 23:15

五一ppt网站(51文档如何下载)

五一ppt网站(51文档如何下载)

今天给各位分享51文档如何下载的知识,其中也会对51文档如何下载进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!本文目录51文档如何下载五一劳动节活动策划书模板10篇51文档如何下载1登陆填写个人信息2来到主界面的话,

2026年3月26日 11:15

doughnut(甜甜圈用英语怎么说)

doughnut(甜甜圈用英语怎么说)

大家好,如果您还对doughnut不太了解,没有关系,今天就由本站为大家分享doughnut的知识,包括甜甜圈用英语怎么说的问题都会给大家分析到,还望可以解决大家的问题,下面我们就开始吧!本文目录甜甜圈用英语怎么说doughnut是什么意思

2026年7月17日 22:15

conventionally a phoneme(conventionally是什么意思)

conventionally a phoneme(conventionally是什么意思)

大家好,关于conventionally a phoneme很多朋友都还不太明白,不过没关系,因为今天小编就来为大家分享关于conventionally是什么意思的知识点,相信应该可以解决大家的一些困惑和问题,如果碰巧可以解决您的问题,还望

2026年2月16日 02:45

css下拉菜单颜色(如何用CSS把下拉菜单背景色弄成透明而上面的文字不透明)

css下拉菜单颜色(如何用CSS把下拉菜单背景色弄成透明而上面的文字不透明)

大家好,css下拉菜单颜色相信很多的网友都不是很明白,包括如何用CSS把下拉菜单背景色弄成透明而上面的文字不透明也是一样,不过没有关系,接下来就来为大家分享关于css下拉菜单颜色和如何用CSS把下拉菜单背景色弄成透明而上面的文字不透明的一些

2025年6月3日 05:45

html5支持的标签(html5 新加的标签元素例如:<header><section><footer>解惑)

html5支持的标签(html5 新加的标签元素例如:<header><section><footer>解惑)

本篇文章给大家谈谈html5支持的标签,以及html5 新加的标签元素例如:解惑对应的知识点,希望对各位有所帮助,不要忘了收藏本站喔。本文目录html5 新加的标签元素例如:解惑html5中标签和标签有什么区别html5 新加的标签元素例如

2025年11月17日 20:30

dom4j生成xml特殊字符不转义(JAVA dom4j怎样将双引号 写入XML时为“ 表示)

dom4j生成xml特殊字符不转义(JAVA dom4j怎样将双引号 写入XML时为“ 表示)

大家好,关于dom4j生成xml特殊字符不转义很多朋友都还不太明白,不过没关系,因为今天小编就来为大家分享关于JAVA dom4j怎样将双引号 写入XML时为“ 表示的知识点,相信应该可以解决大家的一些困惑和问题,如果碰巧可以解决您的问题,

2025年12月14日 22:45

headerstyles设表头样式(word怎么绘制表头斜线并打字)

headerstyles设表头样式(word怎么绘制表头斜线并打字)

大家好,如果您还对headerstyles设表头样式不太了解,没有关系,今天就由本站为大家分享headerstyles设表头样式的知识,包括word怎么绘制表头斜线并打字的问题都会给大家分析到,还望可以解决大家的问题,下面我们就开始吧!本文

2026年8月7日 22:15

近期文章

本站热文

electronics软件(labcenter electronics是什么软件)
2025-05-22 23:45:02 浏览:134
博客是微博吗(博客是微博吗)
2025-05-22 22:45:01 浏览:111
diversity and distribution(悬赏英语短文)
2025-05-23 16:15:02 浏览:107
ios软件开发前景(iOS就业前景怎么样)
2025-05-22 23:00:01 浏览:102
next month(有The next month这个单词吗,和 next month有什么区别)
2025-05-23 02:30:01 浏览:102
patron(patron是什么意思)
2025-05-23 10:30:02 浏览:95
标签列表

热门搜索