淺析Java中的四種執行緒池
阿新 • • 發佈:2018-12-12
1.使用執行緒池的好處
2.JUC中幾種常用的執行緒池
java.util.concurrent包下的Executors工廠類,提供了一系列的執行緒池的建立方法,其構造方法如下:
public ThreadPoolExecutor(int corePoolSize, //執行緒池執行緒核心數量,執行緒池維護執行緒的最少數量 int maximumPoolSize, //執行緒池最大執行緒數量 long keepAliveTime, //空閒執行緒存活時間 TimeUnit unit, //存活時間的時間單位 BlockingQueue<Runnable> workQueue, //儲存任務的執行緒佇列 ThreadFactory threadFactory, //執行緒工廠 RejectedExecutionHandler handler) { //拒絕策略 if (corePoolSize < 0 || maximumPoolSize <= 0 || maximumPoolSize < corePoolSize || keepAliveTime < 0) throw new IllegalArgumentException(); if (workQueue == null || threadFactory == null || handler == null) throw new NullPointerException(); this.corePoolSize = corePoolSize; this.maximumPoolSize = maximumPoolSize; this.workQueue = workQueue; this.keepAliveTime = unit.toNanos(keepAliveTime); this.threadFactory = threadFactory; this.handler = handler; }
其中常用的執行緒池有四種,分別是fixedThreadPool、cachedThreadPool、ScheduledThreadPool和SingleThreadExecutor。他們分別適用在不同的場合。
2.1 newFixedThreadPool
特點:
-
- 用於建立一個可重用、固定執行緒數量的執行緒池;
- 當執行緒池中執行緒都處於執行中時,新來的執行緒會進入等待狀態,直到執行緒池中出現一個空閒執行緒;
- 當一個執行緒在任務中途退出、終止時,會有一個新的執行緒來替代它繼續完成後面未完成的任務。
- 除非採用顯式關閉的方法去關閉某個執行緒,否則執行緒會一直存在,不會釋放資源。
- 任務儲存在無界阻塞佇列中
- 適用場景:長期任務
構造方法:
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); }
例項程式碼:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.junit.Test;
public class ExecutorsTest extends Thread{
private int index;
public ExecutorsTest(int i)
{
this.index = i;
}
public void run()
{
try
{
System.out.println("[Thread"+this.index+"]" +"start..");
Thread.sleep((int)(Math.random()*10000));
System.out.println("[Thread"+this.index+"]" + "end");
}catch(Exception e)
{
e.printStackTrace();
}
}
public static void main(String args[])
{
ExecutorService service = Executors.newFixedThreadPool(4);
for(int i=0;i<10;i++)
{
service.execute(new ExecutorsTest(i));
}
service.shutdown();
}
}
因為執行緒池中執行緒數量一共有4個,所以當一次有大於4個的任務需要執行時,因為執行緒池中無空閒執行緒,後續任務進入等待狀態,當其他任務執行完畢後,執行緒空閒,則馬上開始執行正在等待的任務。
2.1 newCachedThreadPool
特點:
- 執行緒池數量上限為:Integer.MaxValue(2147483647);
- 執行緒池預設空閒60S,超過60S會從執行緒池中移除;
- 新來任務時,先檢查是否有空閒執行緒可使用,若無,則建立一個新執行緒執行任務;
- 任務儲存在同步佇列中。
- 適用場景:短時非同步任務。
建構函式:
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
示例程式碼:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.junit.Test;
public class ExecutorsTest extends Thread{
private int index;
public ExecutorsTest(int i)
{
this.index = i;
}
public void run()
{
try
{
System.out.println("[Thread"+this.index+"]" +"start..");
Thread.sleep((int)(Math.random()*1000));
System.out.println("[Thread"+this.index+"]" + "end");
}catch(Exception e)
{
e.printStackTrace();
}
}
public static void main(String args[])
{
ExecutorService service = Executors.newCachedThreadPool();
for(int i=0;i<10;i++)
{
service.execute(new ExecutorsTest(i));
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
for(int i=0;i<5;i++)
{
service.execute(new ExecutorsTest(i));
}
service.shutdown();
}
建立10個工作執行緒用於處理任務,當執行緒執行完畢後,處於空閒狀態,此時若出現新的任務,則會從執行緒池中用空閒的執行緒來處理新的任務。若沒有空閒執行緒,則開啟新執行緒處理。
2.3 newSingleThreadExecutor
特點:
- 建立一個單個Worker的執行緒;
- 執行緒會按照順序依次執行;
- 任務儲存在無界阻塞佇列中
- 適用場景:需要按照順序執行的任務。
構造方法:
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
例項程式碼:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.junit.Test;
public class ExecutorsTest extends Thread{
private int index;
public ExecutorsTest(int i)
{
this.index = i;
}
public void run()
{
try
{
System.out.println("[Thread"+this.index+"]" +"start..");
Thread.sleep((int)(Math.random()*1000));
System.out.println("[Thread"+this.index+"]" + "end");
}catch(Exception e)
{
e.printStackTrace();
}
}
public static void main(String args[])
{
ExecutorService service = Executors.newSingleThreadExecutor();
for(int i=0;i<10;i++)
{
service.execute(new ExecutorsTest(i));
}
service.shutdown();
}
}
出現多個任務時,SingleThreadExecutor會按照順序依次執行各個任務。
2.4 newScheduledThreadPool
特點:
- 任務儲存在無界延遲佇列中
- 適用場景:需要定期執行或延遲執行的任務
構造方法:
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
例項程式碼一(scheduleAtFixedRate的使用):
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ExecutorsTest2 extends Thread{
private int index;
public ExecutorsTest2()
{
}
public void run()
{
try
{
System.out.println("[Current Time is "+new Date().toString());
}catch(Exception e)
{
e.printStackTrace();
}
}
public static void main(String args[])
{
/*
* 執行定時任務newScheduledThreadPool
*/
ScheduledExecutorService service = Executors.newScheduledThreadPool(10);
//5秒後開始執行,每隔一秒執行一次
service.scheduleAtFixedRate(new ExecutorsTest2(), 5, 1, TimeUnit.SECONDS);
}
}
scheduleAtFixedRate方法,一共四個引數,分別是:需要執行的任務task、延遲執行時間t1、每次執行任務的時間間隔t2、時間間隔單位。 含義是:在t1時間過後,以 1次/t2 的頻率來不斷執行 task。 上述程式碼中,在5秒延遲後,以 1次/1秒的頻率執行 列印當前時間的任務。
例項程式碼二(scheduleWithFixedDelay的使用):
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ExecutorsTest3 extends Thread{
private int index;
public ExecutorsTest3()
{
}
public void run()
{
try
{
//每次任務大約耗時1秒
Thread.sleep(1000);
System.out.println("[Current Time is "+new Date().toString());
}catch(Exception e)
{
e.printStackTrace();
}
}
public static void main(String args[])
{
/*
* 執行定時任務newScheduledThreadPool
*/
ScheduledExecutorService service = Executors.newScheduledThreadPool(10);
//5秒後開始執行,每次任務執行完後延遲3秒後,繼續執行下一次
service.scheduleWithFixedDelay(new ExecutorsTest3(), 5, 3, TimeUnit.SECONDS);
}
}
scheduleWithFixedDelay也是四個引數,分別是:待執行的任務Task,延遲時間t1,每次任務執行完畢後延遲t2秒後執行下次任務,延遲時間單位。
我有一個微信公眾號,經常會分享一些Java技術相關的乾貨;如果你喜歡我的分享,可以用微信搜尋“Java團長”或者“javatuanzhang”關注。