共计 5281 个字符,预计需要花费 14 分钟才能阅读完成。
线程池的创立
线程池的创立调用上面构造函数
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler)
- corePoolSize:线程池外围线程数最大值
- maximumPoolSize:线程池最大线程数大小
- keepAliveTime:线程池中非核心线程闲暇的存活工夫大小
- unit:线程闲暇存活工夫单位
- workQueue:寄存工作的阻塞队列
- threadFactory:用于设置创立线程的工厂,能够给创立的线程设置有意义的名字,可不便排查问题。
- handler:线程池的饱和策略事件,次要有四种类型。
工作执行
线程池执行流程,即对应 execute()办法:提交一个工作,线程池里存活的外围线程池数小于线程数 corePoolSize 时,线程池会创立一个外围线程去解决提交的工作。如果线程池外围线程数已满,即线程池数曾经等于 corePoolSize,一个新提交的工作,会被放进工作队列 workQueue 排队期待执行。当线程池外面存活的线程数曾经等于 corePoolSize 了,并且工作队列 workQueue 也满了,判断线程数是否达到 maximumPoolSize,即最大线程数是否已满,如果没达到,创立一个非核心线程执行提交的工作。如果以后的线程数达到了 maximumPoolSize,还有新的工作过去的话,间接采纳回绝策略解决。
四种回绝策略
- AbortPolicy(抛出一个异样,默认的)
- DiscardPolicy(间接抛弃工作)
- DiscardOldestPolicy(抛弃队列里最老的工作,将以后这个工作持续提交给线程池)
- CallerRunsPolicy(交给线程池调用所在的线程进行解决)
线程池异样解决
在应用线程池解决工作的时候,工作代码可能抛出 RuntimeException,抛出异样后,线程池可能捕捉它,也可能创立一个新的线程来代替异样线程,咱们可能无奈感知工作呈现了异样,因而咱们须要思考线程池异常情况。
线程池的工作队列
- ArrayBlockingQueue
- LinkedBlockingQueue
- DelayQueue
- PriorityBlockingQueue
- SynchronousQueue
ArrayBlockingQueue
ArrayBlockingQueue(有界队列)是一个用数组实现的有界阻塞队列,按 FIFO 排序
LinkedBlockingQueue
LinkedBlockingQueue(可设置容量队列)基于链表构造的阻塞队列,按 FIFO 排序工作,容量能够进行抉择设置,不设置的话,将是一个无边界的阻塞队列,最大长度为 Integer 的 MAX_VALUE,吞吐量通常要高于 ArrayBlockingQueue,newFIxedThreadPool 线程池应用了这个队列。
DelayQueue
DelayQueue(提早队列)是一个工作定时周期的提早执行的队列。依据指定的执行工夫从小到大排序,否则依据插入到队列的先后排序,newScheduledThreadPool 线程池应用了这个队列。
PriorityBlockingQueue
PriorityBlockingQueue(优先级队列)是具备优先级的无界阻塞队列
SynchronousQueue
SynchronousQueue(同步队列)一个不存储元素的阻塞队列,每个插入擦欧洲哦必须等到另一个线程调用移除操作,否则插入操作始终处于阻塞状态,吞吐量通常要高于 LinkedBlockingQueue,newCachedThreadPool 线程池应用了这个队列
几种罕用的线程池
- newFixedThreadPool(固定数目线程的线程池)
- newCachedThreadPool(可缓存线程的线程池)
- newSingleThreadExecutor(单线程的线程池)
- newScheduledThreadPool(定时及周期执行的线程池)
newFixedThreadPool
public static ExecutorService newFixedThreadPool(int nThreads,ThreadFactory threadFactory){
return new ThreadPoolExecutor(nThreads,nThreads,TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory);
线程池特点
外围线程数和最大线程数大小一样
没有所谓的非闲暇工夫,即 keepAliveTime 为 0
阻塞队列为无界队列 LinkedBlockingQueue
解决逻辑
如果线程数少于外围线程,创立外围线程执行工作
如果线程数等于外围线程,把工作增加到 LinkedBlockingQueue 阻塞队列
如果线程执行完工作,去阻塞队列取工作,继续执行。
例子
ExecutorService executor = Executors.newFixedThreadPool(10);
for(int i = 0;i<Integer.MAX_VALUE;i++){executor.execute(()->{
try{Thread.sleep(10000);
}catch(InterruptedException e){}}
}
应用无界队列的线程池会导致内存飙升,newFixedThreadPool 应用了无界的阻塞队列 LinkedBlockingQueue,如果线程获取一个工作后,工作的执行工夫比拟长(比方,下面 demo 设置了 10 秒),会导致队列的工作越积越多,导致机器内存应用不停飙升,最终导致 OOM。newFixedThreadPool 实用于解决 CPU 密集型的工作,确保 CPU 在长期被工作线程应用的状况下,尽可能少的调配线程,即实用执行长期的工作。
newCachedThreadPool
public static ExecutorService newCachedThreadPool(ThreadFactory threadfactory{return new ThreadPoolExecutor(0,INteger.MAX_VALUE,60L,TimeUnit.SECONDS,new SynchronousQueue<Runnable>(),threadFactory);
}
线程池特点
外围线程数为 0
最大线程数为 Integer。MAX_VALUE
阻塞队列是 SynchronousQueue
非核心线程闲暇存活工夫为 60 秒
当提交工作的速度大于解决工作的速度时,每次提交一个工作,就必然会创立一个线程。极其状况下会创立过多的线程,耗尽 CPU 和内存资源。
因为闲暇 60 秒的线程会被终止,长时间放弃闲暇的 CachedThreadPool 不会占用任何资源。
解决逻辑
因为没有外围线程,所有工作间接加到 SynchronousQueue 队列
判断是否有闲暇线程,如果有,就去取出工作执行
如果没有闲暇线程,就新建一个线程执行
执行完工作的线程,还能够存活 60 秒,如果在这期间,接到工作,能够持续活下去;否则,被销毁。
例子
ExecutorService executor = Executors.newCachedThreadPool();
for(int i = 0;i<5;i++){executor.execute(()->{System.out.println(Thread.currentThread().getName()+"正在执行");
});
应用场景
用于并发执行大量短期的小工作
newSingleThreadExecutor
public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFActory){return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1,1,0L,TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>(),threadFactory));
}
线程池特点
外围线程数为 1
最大线程数也为 1
阻塞队列是 LinkedBlockingQueue
keepAliveTime 为 0
解决逻辑
线程池是否有一条线程在,如果没有,新建线程执行工作。如果有,将工作加到阻塞队列。
以后的惟一线程,从队列取工作,执行完一个,再持续取,一个人(一条线程)披星戴月地干活。
ExecutorService executor = Executors.newSingleThreadExecutor();
for(int i =0 ;i<5;i++){executor.execute(()->{System.out.println(Thread.currentThread().getName()+"正在执行");
});
}
应用场景
实用于串行执行工作的场景,一个工作一个工作地执行
newScheduledThreadPool
public ScheduledThreadPoolExecutor(int corePoolSize){super(corePoolSize,Integer.MAX_VALUE,0,NANOSECONDS,new DelayedWorkQueue());
}
线程池特点
最大线程数为 Integer.MAX_VALUE
阻塞队列是 DelayedWorkQueue
keepAliveTime 为 0
scheduleAtFixedRate():按某种速率周期执行
scheduleWithFixedDelay():在某个提早后执行
解决逻辑
线程池中的线程从 DelayQueue 中取工作,线程从 delayQueue 中获取 time 大于等于以后工夫的 task
执行完后批改这个 task 的 time 为下次被执行的工夫,这个 task 放回 DelayQueue 队列中
ScheduleExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
scheduleExecutorService.scheduleWithFixeddelay(()->{System.out.println("current Time"+System.currentTimeMillis());
System.out.println(Thread.currentThread().getName()+"正在执行");
},1,3,TimeUnit.SECONDS);
scheduledExecutorService.scheduleAtFixedRate(()->{System.out.println("current Time" + System.currentTimeMillis());
System.out.println(Thread.currentThread().getName()+"正在执行");
}, 1, 3, TimeUnit.SECONDS);
应用场景
周期性执行工作的场景,须要限度线程数量的场景
线程池状态
线程池有这几个状态:RUNNING,SHUTDOWN,STOP,TIDYING,TERMINATED
private static final int RUNNING = -1<<COUNT_BITS;
private static final int SHUTDOWN = 0<<COUNT_BITS;
private static final int STOP = 1<<COUNT_BITS;
private static final int TIDYING = 2<<COUNT_BITS;
private static final int TERMINATED = 3<<COUNT_BITS;
RUNNING
该状态的线程池会接管新工作,并解决阻塞队列中的工作;
调用线程池的 shutdown()办法。能够切换到 SHUTDOWN 状态
调用线程池的 shutdownNow()办法。能够切换到 STOP 状态
SHUTDOWN
该状态的线程池不会接管新工作,但会解决阻塞队列中的工作
队列为空,并且线程池中执行的工作也为空,进入 TIDYING 状态
STOP
该状态的线程不会接管新工作,也不会解决阻塞队列中的工作,而且会中断正在运行的工作;
线程池中执行的工作为空,进入 TIDYING 状态
TIDYING
该状态表明所有的工作曾经运行终止,记录的工作数量为 0
terminated()执行结束,进入 TERMINATED 状态
TERMINATED
该状态示意线程池彻底终止