每次new Thread()耗費性能
調用new Thread()建立的線程缺少管理,被稱爲野線程,並且能夠無限制建立,之間相互競爭,會致使過多佔用系統資源致使系統癱瘓。
不利於擴展,好比如定時執行、按期執行、線程中斷javascript
重用存在的線程,減小對象建立、消亡的開銷,性能佳
可有效控制最大併發線程數,提升系統資源的使用率,同時避免過多資源競爭,避免堵塞
提供定時執行、按期執行、單線程、併發數控制等功能html
在Java 5以後,併發編程引入了一堆新的啓動、調度和管理線程的API。java
其內部使用了線程池機制,它在java.util.cocurrent 包下,經過該框架來控制線程的啓動、執行和關閉,能夠簡化併發編程的操做。所以,在Java 5以後,經過Executor來啓動線程比使用Thread的start方法更好,除了更易管理,效率更好(用線程池實現,節約開銷)外,還有關鍵的一點:有助於避免this逃逸問題——若是咱們在構造器中啓動一個線程,由於另外一個任務可能會在構造器結束以前開始執行,此時可能會訪問到初始化了一半的對象用Executor在構造器中。面試
Executor框架包括:線程池,Executor,Executors,ExecutorService,CompletionService,Future,Callable等。編程
經過Executors提供四種線程池,newFixedThreadPool、newCachedThreadPool、newSingleThreadExecutor、newScheduledThreadPool。緩存
1.public static ExecutorService newFixedThreadPool(int nThreads)
建立固定數目線程的線程池。服務器
2.public static ExecutorService newCachedThreadPool()
建立一個可緩存的線程池,調用execute將重用之前構造的線程(若是線程可用)。若是現有線程沒有可用的,則建立一個新線 程並添加到池中。終止並從緩存中移除那些已有 60 秒鐘未被使用的線程。微信
3.public static ExecutorService newSingleThreadExecutor()
建立一個單線程化的Executor。markdown
4.public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
建立一個支持定時及週期性的任務執行的線程池,多數狀況下可用來替代Timer類。多線程
示例
ExecutorService executorService = Executors.newFixedThreadPool(5);
for (int i = 0; i < 20; i++) {
Runnable syncRunnable = new Runnable() {
@Override
public void run() {
Log.e(TAG, Thread.currentThread().getName());
}
};
executorService.execute(syncRunnable);
}
運行結果:總共只會建立5個線程, 開始執行五個線程,當五個線程都處於活動狀態,再次提交的任務都會加入隊列等到其餘線程運行結束,當線程處於空閒狀態時會被下一個任務複用
示例:
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 0; i < 100; i++) {
Runnable syncRunnable = new Runnable() {
@Override
public void run() {
Log.e(TAG, Thread.currentThread().getName());
}
};
executorService.execute(syncRunnable);
}
運行結果:能夠看出緩存線程池大小是不定值,能夠須要建立不一樣數量的線程,在使用緩存型池時,先查看池中有沒有之前建立的線程,若是有,就複用.若是沒有,就新建新的線程加入池中,緩存型池子一般用於執行一些生存期很短的異步型任務
schedule(Runnable command,long delay, TimeUnit unit)建立並執行在給定延遲後啓用的一次性操做
示例:表示從提交任務開始計時,5000毫秒後執行
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(5);
for (int i = 0; i < 20; i++) {
Runnable syncRunnable = new Runnable() {
@Override
public void run() {
Log.e(TAG, Thread.currentThread().getName());
}
};
executorService.schedule(syncRunnable, 5000, TimeUnit.MILLISECONDS);
}
運行結果和newFixedThreadPool相似,不一樣的是newScheduledThreadPool是延時必定時間以後才執行
建立並執行一個在給定初始延遲後首次啓用的按期操做,後續操做具備給定的週期;也就是將在 initialDelay 後開始執行,而後在initialDelay+period 後執行,接着在 initialDelay + 2 * period 後執行,依此類推
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(5);
Runnable syncRunnable = new Runnable() {
@Override
public void run() {
Log.e(TAG, Thread.currentThread().getName());
}
};
executorService.scheduleAtFixedRate(syncRunnable, 5000, 3000, TimeUnit.MILLISECONDS);
建立並執行一個在給定初始延遲後首次啓用的按期操做,隨後,在每一次執行終止和下一次執行開始之間都存在給定的延遲
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(5);
Runnable syncRunnable = new Runnable() {
@Override
public void run() {
Log.e(TAG, Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
executorService.scheduleWithFixedDelay(syncRunnable, 5000, 3000, TimeUnit.MILLISECONDS);
ExecutorService executorService = Executors.newSingleThreadExecutor();
for (int i = 0; i < 20; i++) {
Runnable syncRunnable = new Runnable() {
@Override
public void run() {
Log.e(TAG, Thread.currentThread().getName());
}
};
executorService.execute(syncRunnable);
}
運行結果:只會建立一個線程,當上一個執行完以後纔會執行第二個
public interface ExecutorService extends Executor {
void shutdown();//順次地關閉ExecutorService,中止接收新的任務,等待全部已經提交的任務執行完畢以後,關閉ExecutorService
List<Runnable> shutdownNow();//阻止等待任務啓動並試圖中止當前正在執行的任務,中止接收新的任務,返回處於等待的任務列表
boolean isShutdown();//判斷線程池是否已經關閉
boolean isTerminated();//若是關閉後全部任務都已完成,則返回 true。注意,除非首先調用 shutdown 或 shutdownNow,不然 isTerminated 永不爲 true。
boolean awaitTermination(long timeout, TimeUnit unit)//等待(阻塞)直到關閉或最長等待時間或發生中斷,timeout - 最長等待時間 ,unit - timeout 參數的時間單位 若是此執行程序終止,則返回 true;若是終止前超時期滿,則返回 false
<T> Future<T> submit(Callable<T> task);//提交一個返回值的任務用於執行,返回一個表示任務的未決結果的 Future。該 Future 的 get 方法在成功完成時將會返回該任務的結果。
<T> Future<T> submit(Runnable task, T result);//提交一個 Runnable 任務用於執行,並返回一個表示該任務的 Future。該 Future 的 get 方法在成功完成時將會返回給定的結果。
Future<?> submit(Runnable task);//提交一個 Runnable 任務用於執行,並返回一個表示該任務的 Future。該 Future 的 get 方法在成功 完成時將會返回 null
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)//執行給定的任務,當全部任務完成時,返回保持任務狀態和結果的 Future 列表。返回列表的全部元素的 Future.isDone() 爲 true。
throws InterruptedException;
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)//執行給定的任務,當全部任務完成時,返回保持任務狀態和結果的 Future 列表。返回列表的全部元素的 Future.isDone() 爲 true。
throws InterruptedException;
<T> T invokeAny(Collection<? extends Callable<T>> tasks)//執行給定的任務,若是在給定的超時期滿前某個任務已成功完成(也就是未拋出異常),則返回其結果。一旦正常或異常返回後,則取消還沒有完成的任務。
throws InterruptedException, ExecutionException;
<T> T invokeAny(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
ExecutorService接口繼承自Executor接口,它提供了更豐富的實現多線程的方法,好比,ExecutorService提供了關閉本身的方法,以及可爲跟蹤一個或多個異步任務執行情況而生成 Future 的方法。 能夠調用ExecutorService的shutdown()方法來平滑地關閉 ExecutorService,調用該方法後,將致使ExecutorService中止接受任何新的任務且等待已經提交的任務執行完成(已經提交的任務會分兩類:一類是已經在執行的,另外一類是尚未開始執行的),當全部已經提交的任務執行完畢後將會關閉ExecutorService。所以咱們通常用該接口來實現和管理多線程。
ExecutorService的生命週期包括三種狀態:運行、關閉、終止。建立後便進入運行狀態,當調用了shutdown()方法時,便進入關閉狀態,此時意味着ExecutorService再也不接受新的任務,但它還在執行已經提交了的任務,當素有已經提交了的任務執行完後,便到達終止狀態。若是不調用shutdown()方法,ExecutorService會一直處在運行狀態,不斷接收新的任務,執行新的任務,服務器端通常不須要關閉它,保持一直運行便可。
一旦Runnable任務傳遞到execute()方法,該方法便會自動在一個線程上執行。下面是是Executor執行Runnable任務的示例代碼:
public class TestCachedThreadPool{
public static void main(String[] args){
ExecutorService executorService = Executors.newCachedThreadPool();
// ExecutorService executorService = Executors.newFixedThreadPool(5);
// ExecutorService executorService = Executors.newSingleThreadExecutor();
for (int i = 0; i < 5; i++){
executorService.execute(new TestRunnable());
System.out.println("************* a" + i + " *************");
}
executorService.shutdown();
}
}
class TestRunnable implements Runnable{
public void run(){
System.out.println(Thread.currentThread().getName() + "線程被調用了。");
}
}
在Java 5以後,任務分兩類:一類是實現了Runnable接口的類,一類是實現了Callable接口的類。二者均可以被ExecutorService執行,可是Runnable任務沒有返回值,而Callable任務有返回值。而且Callable的call()方法只能經過ExecutorService的submit(Callable task) 方法來執行,而且返回一個 Future,是表示任務等待完成的 Future。
public class CallableDemo{
public static void main(String[] args){
ExecutorService executorService = Executors.newCachedThreadPool();
List<Future<String>> resultList = new ArrayList<Future<String>>();
//建立10個任務並執行
for (int i = 0; i < 10; i++){
//使用ExecutorService執行Callable類型的任務,並將結果保存在future變量中
Future<String> future = executorService.submit(new TaskWithResult(i));
//將任務執行結果存儲到List中
resultList.add(future);
}
//遍歷任務的結果
for (Future<String> fs : resultList){
try{
while(!fs.isDone);//Future返回若是沒有完成,則一直循環等待,直到Future返回完成
System.out.println(fs.get()); //打印各個線程(任務)執行的結果
}catch(InterruptedException e){
e.printStackTrace();
}catch(ExecutionException e){
e.printStackTrace();
}finally{
//啓動一次順序關閉,執行之前提交的任務,但不接受新任務
executorService.shutdown();
}
}
}
}
class TaskWithResult implements Callable<String>{
private int id;
public TaskWithResult(int id){
this.id = id;
}
/** * 任務的具體過程,一旦任務傳給ExecutorService的submit方法, * 則該方法自動在一個線程上執行 */
public String call() throws Exception {
System.out.println("call()方法被自動調用!!! " + Thread.currentThread().getName());
//該返回結果將被Future的get方法獲得
return "call()方法被自動調用,任務返回的結果是:" + id + " " + Thread.currentThread().getName();
}
}
從結果中能夠一樣能夠看出,submit也是首先選擇空閒線程來執行任務,若是沒有,纔會建立新的線程來執行任務。另外,須要注意:若是Future的返回還沒有完成,則get()方法會阻塞等待,直到Future完成返回,能夠經過調用isDone()方法判斷Future是否完成了返回。
自定義線程池,能夠用ThreadPoolExecutor類建立,它有多個構造方法來建立線程池,用該類很容易實現自定義的線程池,這裏先貼上示例程序:
public class ThreadPoolTest{
public static void main(String[] args){
//建立等待隊列
BlockingQueue<Runnable> bqueue = new ArrayBlockingQueue<Runnable>(20);
//建立線程池,池中保存的線程數爲3,容許的最大線程數爲5
ThreadPoolExecutor pool = new ThreadPoolExecutor(3,5,50,TimeUnit.MILLISECONDS,bqueue);
//建立七個任務
Runnable t1 = new MyThread();
Runnable t2 = new MyThread();
Runnable t3 = new MyThread();
Runnable t4 = new MyThread();
Runnable t5 = new MyThread();
Runnable t6 = new MyThread();
Runnable t7 = new MyThread();
//每一個任務會在一個線程上執行
pool.execute(t1);
pool.execute(t2);
pool.execute(t3);
pool.execute(t4);
pool.execute(t5);
pool.execute(t6);
pool.execute(t7);
//關閉線程池
pool.shutdown();
}
}
class MyThread implements Runnable{
@Override
public void run(){
System.out.println(Thread.currentThread().getName() + "正在執行。。。");
try{
Thread.sleep(100);
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
http://gold.xitu.io/entry/57cbaf667db2a2007895256e
http://blog.csdn.net/ns_code/article/details/17465497
http://www.infoq.com/cn/articles/executor-framework-thread-pool-task-execution-part-01
http://www.cnblogs.com/limingluzhu/p/4858776.html