线程池使用场景
2021-09-09 本文已影响0人
芝兰之室也
Java提供四种线程池,分别对应不同的应用场景
考虑多线程因素:
任务数、任务执行时间、线程数、CPU核数
1、newCachedThreadPool
创建一个线程池,如果线程池中的线程数量过大,它可以有效的回收多余的线程,如果线程数不足,那么它可以创建新的线程。
- 它是一个可以无限扩大的线程池(corePoolSize为0,maximumPoolSize为无限大意味着线程数量可以无限大);
- 它比较适合处理执行时间比较小的任务(keepAliveTime为60s,意味着线程空闲时间超过60s就会被杀死);
- 它采用SynchronousQueue装等待的任务,这个阻塞队列没有存储空间,意味着只要有请求到来,就必须要找到一条工作线程处理他,如果当前没有空闲的线程,那么就会再创建一条新的线程。
代码示例:
ExecutorService cachePool = Executors.newCachedThreadPool();
for(int i=0;i<5;i++){
cachePool.execute(() -> {
System.out.println(Thread.currentThread().getName());
});
}
输出:每个任务都会起一个线程,无限扩大
pool-1-thread-1
pool-1-thread-2
pool-1-thread-3
pool-1-thread-4
pool-1-thread-5
2、newFixedThreadPool
- 它是一种固定大小的线程池(corePoolSize、maximunPoolSize都为用户设定的线程数量nThreads);
- 阻塞队列采用了LinkedBlockingQueue,它是一个无界队列(实际线程数量将永远维持在nThreads),因此永远不可能拒绝任务;
代码示例:
ExecutorService fixedPool = Executors.newFixedThreadPool(3);
for(int i=0; i<5; i++){
fixedPool.execute(() -> {
System.out.println(Thread.currentThread().getName());
});
}
输出:
pool-2-thread-1
pool-2-thread-3
pool-2-thread-1
pool-2-thread-2
pool-2-thread-3
固定线程池大小为3,需要5个线程,所以前3个线程就存在线程复用的情况。
当任务执行存在时延时,前三个线程就不会出现线程复用的情况了:
ExecutorService fixedPool = Executors.newFixedThreadPool(3);
for(int i=0; i<5; i++){
fixedPool.execute(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+":"+System.currentTimeMillis()/1000);
});
}
输出:任务耗时一秒,前三个线程没有复用
pool-1-thread-3:1631157921
pool-1-thread-1:1631157921
pool-1-thread-2:1631157921
pool-1-thread-1:1631157922
pool-1-thread-2:1631157922
3、ScheduledThreadPool
- 它用来处理延时任务或定时任务;
- 它采用DelayQueue存储等待的任务,是一个无界队列,内部封装了一个PriorityQueue,它会根据time的先后时间排序,若time相同则根据sequenceNumber排序;
- 工作过程:任务线程会从DelayQueue取已经到期的任务去执行,执行结束后重新设置任务的到期时间,再次放回DelayQueue。
代码示例:
(1)定时任务:scheduleAtFixedRate
- 表示上一个任务开始和下一个任务开始之间,间隔一个period;
- 如果上一个任务执行完毕,则当前任务立即执行,如果上一个任务没有执行完毕,则需要等上一个任务执行完毕后立即执行。
a)任务执行时间小于period,则以period定时处理任务
ScheduledExecutorService schedPool = Executors.newScheduledThreadPool(3);
for (int i = 0; i < 3; i++) {
schedPool.scheduleAtFixedRate(() ->{
System.out.println(Thread.currentThread().getName()+":"+System.currentTimeMillis()/1000);
}, 0,3, TimeUnit.SECONDS);
}
输出:
pool-1-thread-1:1631176308
pool-1-thread-1:1631176308
pool-1-thread-1:1631176308
pool-1-thread-1:1631176311
pool-1-thread-3:1631176311
pool-1-thread-1:1631176311
pool-1-thread-3:1631176314
pool-1-thread-1:1631176314
pool-1-thread-2:1631176314
b)若任务执行时间大于period,则以执行时间定时处理任务
ScheduledExecutorService schedPool = Executors.newScheduledThreadPool(3);
for (int i = 0; i < 3; i++) {
schedPool.scheduleAtFixedRate(() ->{
System.out.println(Thread.currentThread().getName()+":"+System.currentTimeMillis()/1000);
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}, 0,3, TimeUnit.SECONDS);
}
输出:
pool-1-thread-2:1631176413
pool-1-thread-3:1631176413
pool-1-thread-1:1631176413
pool-1-thread-2:1631176417
pool-1-thread-1:1631176417
pool-1-thread-3:1631176417
pool-1-thread-3:1631176421
pool-1-thread-2:1631176421
pool-1-thread-1:1631176421
(2)延时任务:scheduleWithFixedDelay
- 表示上一个任务结束和下一个任务开始之间,时间间隔为一个delay
任务执行时间为4秒,延时为3秒,所以每个任务之间间隔7秒
ScheduledExecutorService schedPool = Executors.newScheduledThreadPool(3);
for (int i = 0; i < 3; i++) {
schedPool.scheduleWithFixedDelay(() ->{
System.out.println(Thread.currentThread().getName()+":"+System.currentTimeMillis()/1000);
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}, 0,3, TimeUnit.SECONDS);
}
输出:
pool-1-thread-1:1631176156
pool-1-thread-3:1631176156
pool-1-thread-2:1631176156
pool-1-thread-3:1631176163
pool-1-thread-1:1631176163
pool-1-thread-2:1631176163
pool-1-thread-1:1631176170
pool-1-thread-2:1631176170
pool-1-thread-3:1631176170
4、 SingleThreadExecutor
- 它只会创建一条工作线程处理任务;
- 采用的阻塞队列为LinkedBlockingQueue;