参考:ThreadPoolExecutor 中的 shutdown() 、 shutdownNow() 、 awaitTermination() 的用法和区别 - 今天代码写完了吗 - 博客园
主线程:
ThreadPoolExecutor threadPoolExecutor = TestThreadPool.getThreadPool(); jzFuture = threadPoolExecutor.submit(new GrOrder(contractnum,orderInfo)); Object obj = jzFuture.get(timeout, TimeUnit.MILLISECONDS); //总超时时间设置
如果主线程超时,则超时后主线程自动向下执行,但线程池中创建的次线程,则需要继续等待response content内容返回,此不会消失,会一直等待,作为活的线程。
其中:
public class GrOrder implements Callable
@Override public Object call() throws Exception {
HttpGet httpGet = new HttpGet("http://ip:port/hi") String response = httpclient.execute(httpGet); return response ; //该线程一直等待,不会释放,一直等待结果 }
*****线程池如果不主动关闭,此不会主动关闭,一直运行,故一定要主动关闭线程池。
线程池关闭或停止时,初始化线程池。其中线程池当没有引用且没有剩余线程时会自动关闭
(1)自定义线程池,可以用 ArrayBlockingQueue有界缓存等待队列,让任务在队列排队
int CORE_THREAD_COUNT = 0;
int MAX_THREAD_COUNT = 1840; //17=2*8+1 或者 (40-80)= CPU核心数/(1-阻塞系数)
long KEEP_ALIVE_TIME = 60L;
TimeUnit ALIVE_TIME_UNIT = TimeUnit.SECONDS;
// BlockingQueue<Runnable> queue = new SynchronousQueue<>();
BlockingQueue<Runnable> queue = new ArrayBlockingQueue(1840);
if(executorServer==null||executorServer.isShutdown()||executorServer.isTerminated()){
synchronized (JzPreCheckUtil.class) {
if (executorServer==null||executorServer.isShutdown()||executorServer.isTerminated()) {
executorServer = new ThreadPoolExecutor(CORE_THREAD_COUNT, MAX_THREAD_COUNT, KEEP_ALIVE_TIME, ALIVE_TIME_UNIT, queue);
}
}
}
(2)、使用CachedThreadPool创建线程池,无核心线程,最大线程数无界(可能OOM),线程闲置60秒后会销毁线程,SynchronousQueue是个长度为0的阻塞队列,适合任务量大但耗时少的任务。
(3)采用拒绝策略CallerRunsPolicy(完全的同步)让调用该线程池的线程执行操作(异步转同步)
(4)动态创建线程池,根据用户数量,动态调整线程池的配置数量,并设置线程数最大值 (无必要,非核心线程有存活时间,同CachedThreadPool)
应用类型包括IO密集型、CPU密集型,IO密集型通常设置为2n+1 (n为CPU核数),CPU密集型通常设置为 n+1,但仅适用于架构;其中生产一般CPU为8核。网上IO密集型类型的应用:线程数 = CPU核心数/(1-阻塞系数),其中,阻塞系数的概念,一般为0.8~0.9之间
c.线程池介绍
i.CachedThreadPool无核心线程,最大线程数无界(可能OOM),线程闲置60秒后会销毁线程,SynchronousQueue是个长度为0的阻塞队列,适合任务量大但耗时少的任务;
//创建使用单个线程的线程池 ExecutorService es1 = Executors.newSingleThreadExecutor(); for (int i = 0; i < 10; i++) { es1.submit(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + "正在执行任务"); } }); }
ii.fixedThreadPool中核心线程和最大线程相同,LinkedBlockingQueue为无界队列(可能OOM);适用于任务量固定耗时长的任务;
iii.singleThreadPool核心线程和最大线程都为1,表示同一时刻最多只会有一个线程。适用于多个任务顺序使用的场景
通过对ThreadPoolExecutor类分析,引发java.util.concurrent.RejectedExecutionException主要有两种原因:
线程池显示的调用了shutdown()之后,再向线程池提交任务的时候,如果你配置的拒绝策略是ThreadPoolExecutor.AbortPolicy的话,这个异常就被会抛出来。
当你的排队策略为有界队列,并且配置的拒绝策略是ThreadPoolExecutor.AbortPolicy,当线程池的线程数量已经达到了maximumPoolSize的时候,你再向它提交任务,就会抛出ThreadPoolExecutor.AbortPolicy异常。
IV .ScheduledThreadPool核心线程数为用户自定义,最大线程数无限制,非核心线程数一空闲立刻销毁。队列采用了一个可对任务按延时时间进行排序的队列,延时时间越短排在最前。这也是个无界队列。这种线程池适合固定周期的定时任务或重复任务。但无界的队列和无限制的最大线程数,意味着它会出现内存溢出和cpu占用率百分百的问题;
d.SynchronousQueue 、 LinkedBlockingQueue 和 ArrayBlockingQueue 区别
i.SynchronousQueue没有容量,是无缓冲等待队列,是一个不存储元素的阻塞队列,会直接将任务交给消费者,必须等队列中的添加元素被消费后才能继续添加新的元素。拥有公平(FIFO)和非公平(LIFO)策略,非公平侧罗会导致一些数据永远无法被消费的情况。使用SynchronousQueue阻塞队列一般要求maximumPoolSizes为无界(Integer.MAX_VALUE),避免线程拒绝执行操作。
ii.LinkedBlockingQueue是一个无界缓存等待队列。当前执行的线程数量达到corePoolSize的数量时,剩余的元素会在阻塞队列里等待,当队列满时,才会开启新的线程,立即执行新添加的任务,当线程数达到 maximumPoolSize 数量时,执行线程拒绝策略。每个线程完全独立于其他线程。生产者和消费者使用独立的锁来控制数据的同步,即在高并发的情况下可以并行操作队列中的数据。
iii. ArrayBlockingQueue是一个有界缓存等待队列,可以指定缓存队列的大小,当正在执行的线程数等于corePoolSize时,多余的元素缓存在ArrayBlockingQueue队列中等待有空闲的线程时继续执行,当ArrayBlockingQueue已满时,加入ArrayBlockingQueue失败,会开启新的线程去执行,当线程数已经达到最大的maximumPoolSizes时,再有新的元素尝试加入ArrayBlockingQueue时会执行拒绝策略。
(4)拒绝策略
AbortPolicy:默认策略,丢弃当前被拒绝的任务,抛出RejectedExecutionException异常。
DiscardPolicy: 这个拒绝策略就是丢弃当前被拒绝的任务,不抛出异常;
DiscardOldestPolicy: 这个拒绝策略就是将最先进入工作队列等待的任务丢弃,然后接受新的任务
CallerRunsPolicy: 这个拒绝策略就是谁调用了本线程池,则谁来执行该任务,保证的任务不会丢失。
(5)线程池当没有引用且没有剩余线程时会自动关闭
ThreadPoolExecutor 中的 shutdown() 、 shutdownNow() 、 awaitTermination() 的用法和区别
shutdown()
将线程池状态置为SHUTDOWN,并不会立即停止:
- 停止接收外部submit的任务
- 内部正在跑的任务和队列里等待的任务,会执行完
- 等到第二步完成后,才真正停止
shutdownNow()
将线程池状态置为STOP。企图立即停止,事实上不一定:
- 跟shutdown()一样,先停止接收外部提交的任务
- 忽略队列里等待的任务
- 尝试将正在跑的任务interrupt中断
- 返回未执行的任务列表
awaitTermination(long timeOut, TimeUnit unit)
当前线程阻塞,直到
- 等所有已提交的任务(包括正在跑的和队列中等待的)执行完
- 或者等超时时间到
- 或者线程被中断,抛出InterruptedException
然后返回true(shutdown请求后所有任务执行完毕)或false(已超时)
shutdown()和awaitTermination()的区别
- shutdown()后,不能再提交新的任务进去;但是awaitTermination()后,可以继续提交。
- awaitTermination()是阻塞的,返回结果是线程池是否已停止(true/false);shutdown()不阻塞。