future.cancel不能关闭线程_java中的线程池有什么作⽤?想要了解线程池,⾸先要理解程序—进程—线程的概念
1. 程序-进程-线程的简单介绍
进程
什么是进程呢?
进程是计算机中的程序关于某数据集合的⼀次运⾏活动,是系统进⾏资源分配的调度的基本单位,是操作系统结构的基础。简单来讲:进程是指运⾏中的应⽤程序,进程是⼀个实体,每⼀个进程都有它⾃⼰的地址空间。例如我们点击了QQ,就启动了⼀个进程,操作系统就会为这个进程分配独⽴的地址空间,当我们⼜点击浏览器,这样⼜启动了⼀个进程,操作系统将为新的进程分配新的独⽴的地址空间。
线程
什么是线程呢?
线程是操作系统能够进⾏运算调度的最⼩单位,被包含在进程之中,是进程中的实际运作单位。⼀个进程⾄少有⼀个线程。⼀条线程指的是进程中⼀个单⼀顺序的控制流,⼀个进程中可以并发多个线程,每
条线程并⾏执⾏不同的任务。注意:线程⾃⼰不拥有系统资源,只拥有⼀点在运⾏中必不可少的资源,但它可与同属于⼀个进程的其他线程共享进程所拥有的全部资源,线程有就绪,阻塞,运⾏三种基本状态。
2.java的线程池是什么,初始化线程池有哪些?
线程池是⼀种多线程处理形式,处理过程中将任务添加队列,然后在创建线程后⾃动启动这些任务,每个线程都使⽤默认的堆栈⼤⼩,以默认的优先级运⾏,并处在多线程单元中,如果某个线程在托管代码中空闲,则线程池将插⼊另⼀个辅助线程来使所有处理器保持繁忙。如果所有线程池都始终保持繁忙,但队列中包含挂起的⼯作,则线程池将在⼀段时间后辅助线程的数⽬永远不会超过最⼤值。超过最⼤值的线程可以排队,但他们要等到其他线程完成后才能启动。
java⾥⾯的线程池的顶级接⼝是Executor,Executor并不是⼀个线程池,⽽只是⼀个执⾏线程的⼯具,⽽真正的线程池是ExecutorService。
初始化4种类型的线程池:
newFixedThreadPool()
说明:初始化⼀个指定线程数的线程池,其中corePoolSize == maxiPoolSize,使⽤LinkedBlockingQuene作为阻塞队列
特点:即使当线程池没有可执⾏任务时,也不会释放线程。
newCachedThreadPool()
说明:初始化⼀个可以缓存线程的线程池,默认缓存60s,线程池的线程数可达到Integer.MAX_VALUE,即2147483647,内部使⽤SynchronousQueue作为阻塞队列;
特点:在没有任务执⾏时,当线程的空闲时间超过keepAliveTime,会⾃动释放线程资源;当提交新任务时,如果没有空闲线程,则创建新线程执⾏任务,会导致⼀定的系统开销;
因此,使⽤时要注意控制并发的任务数,防⽌因创建⼤量的线程导致⽽降低性能。
newSingleThreadExecutor()
说明:初始化只有⼀个线程的线程池,内部使⽤LinkedBlockingQueue作为阻塞队列。
特点:如果该线程异常结束,会重新创建⼀个新的线程继续执⾏任务,唯⼀的线程可以保证所提交任务的顺序执⾏
newScheduledThreadPool()
特定:初始化的线程池可以在指定的时间内周期性的执⾏所提交的任务,在实际的业务场景中可以使⽤该线程池定期的同步数据。
ThreadPoolExecutor内部具体实现:
线程池的状态(5种)
其中AtomicInteger变量ctl的功能⾮常强⼤:利⽤低29位表⽰线程池中线程数,通过⾼3位表⽰线程池的运⾏状态:
1、RUNNING:-1 << COUNT_BITS,即⾼3位为111,该状态的线程池会接收新任务,并处理阻塞队列中的任务;
2、SHUTDOWN: 0 << COUNT_BITS,即⾼3位为000,该状态的线程池不会接收新任务,但会处理阻塞队列中的任务;
3、STOP : 1 << COUNT_BITS,即⾼3位为001,该状态的线程不会接收新任务,也不会处理阻塞队列中的任务,⽽且会中断正在运⾏的任务;
4、TIDYING : 2 << COUNT_BITS,即⾼3位为010,该状态表⽰线程池对线程进⾏整理优化;
5、TERMINATED: 3 << COUNT_BITS,即⾼3位为011,该状态表⽰线程池停⽌⼯作;
向线程池提交任务(2种)
有两种⽅式:
ExecutorService.submit(Callable task);
execute()内部实现
1.⾸次通过workCountof()获知当前线程池中的线程数,
如果⼩于corePoolSize, 就通过addWorker()创建线程并执⾏该任务;
否则,将该任务放⼊阻塞队列;
2. 如果能成功将任务放⼊阻塞队列中,
如果当前线程池是⾮RUNNING状态,则将该任务从阻塞队列中移除,然后执⾏reject()处理该任务;
java线程池创建的四种如果当前线程池处于RUNNING状态,则需要再次检查线程池(因为可能在上次检查后,有线程资源被释放),是否有空闲的线程;如果有则执⾏该任务;
3、如果不能将任务放⼊阻塞队列中,说明阻塞队列已满;那么将通过addWoker()尝试创建⼀个新的线程去执⾏这个任务;如果addWoker()执⾏失败,说明线程池中线程数达到maxPoolSize,则执⾏reject()处理任务;
sumbit()内部实现
会将提交的Callable任务会被封装成了⼀个FutureTask对象
FutureTask类实现了Runnable接⼝,这样就可以通过ute()提交FutureTask到线程池中等待被执⾏,最终执⾏的是FutureTask的run⽅法;
⽐较:
两个⽅法都可以向线程池提交任务,execute()⽅法的返回类型是void,它定义在Executor接⼝中, ⽽submit()⽅法可以返回持有计算结果的Future对象,它定义在ExecutorService接⼝中,它扩展了Executor接⼝,其它线程池类像ThreadPoolExecutor和ScheduledThreadPoolExecutor都有这些⽅法。
线程池的关闭(2种)
ThreadPoolExecutor提供了两个⽅法,⽤于线程池的关闭,分别是shutdown()和shutdownNow(),其中:
shutdown():不会⽴即终⽌线程池,⽽是要等所有任务缓存队列中的任务都执⾏完后才终⽌,但再也不会接受新的任务
shutdownNow():⽴即终⽌线程池,并尝试打断正在执⾏的任务,并且清空任务缓存队列,返回尚未执⾏的任务
线程池容量的动态调整
ThreadPoolExecutor提供了动态调整线程池容量⼤⼩的⽅法:setCorePoolSize()和setMaximumPoolSize(),
总结:
线程池中的核⼼线程数,当提交⼀个任务时,线程池创建⼀个新线程执⾏任务,直到当前线程数等于corePoolSize;如果当前线程数为corePoolSize,继续提交的任务被保存到阻塞队列中,等待被执⾏;如果阻塞队列满了,那就创建新的线程执⾏当前任务;直到线程池中的线程数达到maxPoolSize,这时再有任务来,只能执⾏reject()处理该任务。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论