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);
}