java线程池详解 官网,Java线程池详解
线程池概述
1.线程池是管理线程的池,可以减少创建和销毁线程所造成的资源消耗。
因为线程实际上是一个对象,创建一个对象需要经历类加载过程,销毁一个对象,经历GC垃圾回收过程,这些都需要资源开销。
2.提高反应速度,任务已经到了。相比从线程池中抓取线程,自己创建线程肯定要慢很多。
3.重用。线程用完了,就放回池中,这样就达到了重用的效果。
(推荐视频:java视频教程)
线程池执行
打个比方。
核心线程被比作公司的正式员工。
非核心线程被比作外包员工。
阻塞队列被比作需求池。
提交任务就像是自讨苦吃。
如何解决写爬虫IP受阻的问题?立即使用。
正式执行
public thread pool executor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit单位,
BlockingQueueRunnable工作队列,
线程工厂线程工厂,
ReordexecutionHandler处理程序)Corepoolsize核心线程
maximumPoolSize线程池中的最大线程数
KeepAliveTime空闲线程生存期
单位时间线程空闲生存期单位
工作队列保存任务的阻塞队列。
螺纹工厂
处理程序饱和策略当一个任务提交后,线程池中存活的核心线程数小于线程数corePoolSize时,线程池会创建一个核心线程来处理提交的任务。
如果线程池中的核心线程数已满,即线程数已经等于corePoolSize,一个新提交的任务将被放入任务队列workQueue等待执行。
当线程池中存活的线程数已经等于corePoolSize,且任务队列的workQueue已满时,判断线程数是否达到maximumPoolSize,即最大线程数是否已满。如果没有,创建一个非核心线程来执行提交的任务。
如果当前线程数达到maximumPoolSize,并且有新任务到来,将直接采用拒绝策略。
几种饱和策略
AbortPolicy抛出异常,默认情况下
丢弃策略直接丢弃任务。
DiscardOldestPolicy会丢弃队列中最早的任务,并继续将当前任务提交给线程池。
CallerRunsPolicy被移交给进行线程池调用的线程,用于处理线程池异常处理
因为调用线程池处理任务过程中的异常可能会被线程池捕获,任务的执行可能是察觉不到的,所以我们需要考虑线程池的异常。
方法1:
@测试
public void test1()引发异常{
ExecutorService ExecutorService=executors . newfixedthreadpool(5);
for(int I=0;i5;i ) {
executorservice . submit(new Runnable(){
@覆盖
公共无效运行(){
尝试{
name: Thread.currentThread()。getName());
对象a=null
system . out . println(a . hashcode());
} catch(异常e) {
system . out . println(e);
}
}
});
}
}方法二:
@测试
public void test2()引发异常{
ExecutorService ExecutorService=executors . newfixedthreadpool(5);
for(int I=0;i 20i ) {
未来?future=executorservice . submit(new Runnable(){
@覆盖
公共无效运行(){
name: Thread.currentThread()。getName());
对象a=null
system . out . println(a . hashcode());
}
});
尝试{
future . get();
} catch(异常e) {
system . out . println(e);
}
}
}线程池的工作队列
ArrayBlockingQueue
LinkedBlockingQueue
同步队列
延迟队列
PriorityBlockingQueue
==ArrayBlockingQueue==
初始化具有一定容量的阵列
使用重入锁,默认为不公平锁。入队和出队共享一个锁,这是互斥的。
是有界设计。如果容量已满,则无法继续添加元素,除非删除一些元素。
使用时,开辟一个连续的记忆。如果初始化容量过大,容易浪费资源;如果太小,很容易添加失败。
==LinkedBlockingQueue==
使用链表数据结构
不连续的存储空间
使用两个重入锁分别控制元素的入队和出队,使用条件在线程间唤醒和等待。
有界,容量为整数。默认构造方法中的MAX_VALUE。
==SynchronousQueue==
内部容量为0。
每次删除都要等待插入操作。
每次插入时等待删除。
一旦有了插入线程和移除线程,元素就被快速地从插入线程转移到移除线程。这个容器相当于一个通道,本身不存储元素。
在多任务队列中,是处理任务最快的方式。
==PriorityBlockingQueue==
无边的设计,但容量其实取决于系统资源的影响。
添加元素,如果超过1,输入优先顺序。
==延迟队列==
无限设计
加(放)不堵,拆堵。
所有元素都有失效时间。
Take元素只有过期才会被取出。
常用的线程池
newFixedThreadPool(具有固定数量线程的线程池)
newCachedThreadPool(可缓存线程的线程池)
newSingleThreadExecutor(单线程的线程池)
newScheduledThreadPool(用于常规和定期执行的线程池)
==newFixedThreadPool==
public static ExecutorService newFixedThreadPool(int nThreads){
返回新的ThreadPoolExecutor(nThreads,nThreads,
0L,时间单位。毫秒,
new LinkedBlockingQueueRunnable());
}特点
1.核心线程的数量与最大线程数量相同。
2.没有所谓的非空闲时间,即keepAliveTime为0
3.阻塞队列是LinkedBlockingQueue的无界队列
工作机制:
提交任务。
如果线程数少于核心线程数,则创建核心线程来执行任务。
如果线程数等于核心线程数,则将任务添加到LinkedBlockingQueue的阻塞队列中。
如果线程完成任务,阻塞队列获取任务,继续执行。
==newCachedThreadPool==
public static ExecutorService newCachedThreadPool(){
返回新的ThreadPoolExecutor(0,整数。最大值,
60L,时间单位。秒,
new SynchronousQueueRunnable());
}线程池特点
核心线程数为0。
最大线程数为整数。最大值
阻塞队列是SynchronousQueue。
非核心线程的空闲存活时间为60秒。
工作机制:
提交任务。
因为没有核心线程,所以任务直接加入SynchronousQueue队列。
判断是否有空闲线程,如果有,取出任务执行。
如果没有空闲线程,则创建一个新线程来执行。
完成任务的线程还能活60秒。如果它在这期间接到任务,就可以继续活下去;不然就毁了。
使用场景
用于并发执行大量短期小任务。
==newSingleThreadExecutor==
线程池特点
核心线程数为1。
最大线程数也是1。
阻塞队列被链接阻塞队列
keepAliveTime为0。
公共静态执行器服务newSingleThreadExecutor(ThreadFactory ThreadFactory){
返回新的FinalizableDelegatedExecutorService
(新的ThreadPoolExecutor(1,1,
0L,时间单位。毫秒,
新LinkedBlockingQueueRunnable(),
thread factory));
}工作机制
提交任务。
线程池中有线程吗?如果没有,请创建一个新线程来执行该任务。
如果是,将任务添加到阻塞队列。
当前唯一的线程,从队列中取任务,执行一个,然后继续取。一个人(一根线)没日没夜的工作。
使用场景
它适用于串行执行任务的场景,一次执行一个任务。
==newScheduledThreadPool==
线程池特点
public scheduled threadpoolexecutor(int corePoolSize){
super(corePoolSize,整数。MAX_VALUE,0,纳秒,new DelayedWorkQueue());
}最大线程数为整数。最大值
阻塞队列是DelayedWorkQueue。
keepAliveTime为0。
scheduleAtFixedRate():以一定的速率周期性执行。
scheduleWithFixedDelay():在一定延迟后执行。
工作机制
添加任务。
线程池中的线程从延迟队列中获取任务。
线程从DelayQueue中获取时间大于等于当前时间的任务。
执行后,修改该任务下次执行的时间。
该任务被放回延迟队列。
scheduleWithFixedDelay
无论任务执行多长时间,第一个任务完成后,延迟指定时间再开始第二个任务。
scheduleAtFixedRate
当任务执行时间小于间隔时间时,程序将以启动时间为基础每隔指定时间执行一次,不受任务执行时间的影响。
当任务执行时间长于间隔时间时,该方法不会重新启动一个新的任务执行,而是等待原任务完成后,立即启动下一个任务执行。此时,执行间隔已被打乱。
本文来自我们,java教程专栏,欢迎学习!以上是java线程池的详细内容。更多请关注我们的其他相关文章!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。