1. 介绍
线程池工厂,在实际生产环境中,线程的数量必须得到控制,盲目的大量创建线程对系统性能是有伤害的。
2. 主要方法
2.1 newFixedThreadPool()
该方法返回一个固定线程数量的线程池,该线程池中的线程数量始终不变,当有一个新的任务提交时,线程池中若有空闲线程,则立即执行,若没有,则新的任务会被暂存在一个任务队列中,待有线程空闲时,便处理在任务队列中的任务。
线程数固定,队列无限大
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
示例:
/**
* newFixedThreadPool
* 若任务生产的速度远远大于任务处理的速度,阻塞队列的容量就会一直变大,有可能产生内存溢出
*/
public class Test01 {
@Test
public void test01() throws Exception{
ExecutorService es = Executors.newFixedThreadPool(3);
for (int i = 0; i < 30; i++) {
es.execute(() -> {
System.out.println(Instant.now().getEpochSecond() + " " + Thread.currentThread().getId());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
Thread.sleep(13000);
}
}
2.2 newSingleThreadExecutor()
该方法返回一个只有一个线程的线程池。若多余一个任务被提交到该线程池,任务会被保存在一个任务队列中,待线程空闲,按先入先出的顺序执行队列中的任务。
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
2.3 newCachedThreadPool()
该方法返回一个可根据实际情况调整线程数量的线程池。线程池的线程数量不确定,但若有空闲线程可以复用,则会优先使用可复用的线程。若所有线程均在工作,又有新的任务提交,则会创建新的线程处理任务。所有线程在当前任务执行完毕后,将返回线程池进行复用。
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
2.4 newSingleThreadScheduledExecutor()
该方法返回一个ScheduledExecutorService对象,线程池大小为1。ScheduledExecutorService接口在ExecutorService接口之上扩展了在给定时间执行某任务的功能,如在某个固定的延时之后执行,或者周期性执行某个任务。
public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
return new DelegatedScheduledExecutorService
(new ScheduledThreadPoolExecutor(1));
}
2.5 newScheduledThreadPool()
该方法也返回一个ScheduledExecutorService对象,但该线程池可以指定线程数量。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
主要有三种用法,实例:
/**
* schedule, 在给定的时间,对任务进行一次调度
*
* @throws Exception
*/
@Test
public void test01() throws Exception {
ScheduledExecutorService es = Executors.newScheduledThreadPool(3);
for (int i = 0; i < 10; i++) {
es.schedule(() -> {
System.out.println("run start " + Thread.currentThread().getId());
}, 2, TimeUnit.SECONDS);
}
Thread.sleep(10000);
}
/**
* scheduleAtFixedRate 以任务开始为时间起点,然后每个period周期执行一次任务,
* 如果执行任务时间超过了周期时间,则任务完成后立即开启下一次任务
*
* 下面例子实际周期变成了5
*
* @throws Exception
*/
@Test
public void test02() throws Exception {
ScheduledExecutorService es = Executors.newScheduledThreadPool(3);
for (int i = 0; i < 1; i++) {
es.scheduleAtFixedRate(() -> {
System.out.println("run start " + Instant.now().getEpochSecond() + " " + Thread.currentThread().getId());
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}, 2, 3, TimeUnit.SECONDS);
}
Thread.sleep(20000);
}
/**
* scheduleWithFixedDelay 以上一个任务结束后为开始计时,delay时间后,下一个线程执行
*
* 下面例子实际周期变成了8
* @throws Exception
*/
@Test
public void test03() throws Exception {
ScheduledExecutorService es = Executors.newScheduledThreadPool(3);
for (int i = 0; i < 1; i++) {
es.scheduleWithFixedDelay(() -> {
System.out.println("run start " + Instant.now().getEpochSecond() + " " + Thread.currentThread().getId());
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}, 2, 3, TimeUnit.SECONDS);
}
Thread.sleep(20000);
}
实时内容请关注微信公众号,公众号与博客同时更新:程序员星星