線程池ExecutorService的submit和execute
線程池ExecutorService的submit和execute
在Java5之后,并發線程這塊發生了根本的變化,最重要的莫過于新的啟動、調度、管理線程的一大堆API了。在Java5以后,通過 Executor來啟動線程比用Thread的start()更好。在新特征中,可以很容易控制線程的啟動、執行和關閉過程,還可以很容易使用線程池的特 性。
一、創建任務
任務就是一個實現了Runnable接口的類。
創建的時候實run方法即可。
二、執行任務
通過java.util.concurrent.ExecutorService接口對象來執行任務,該接口對象通過工具類java.util.concurrent.Executors的靜態方法來創建。
Executors此包中所定義的 Executor、ExecutorService、ScheduledExecutorService、ThreadFactory 和 Callable 類的工廠和實用方法。
ExecutorService提供了管理終止的方法,以及可為跟蹤一個或多個異步任務執行狀況而生成 Future 的方法。 可以關閉 ExecutorService,這將導致其停止接受新任務。關閉后,執行程序將最后終止,這時沒有任務在執行,也沒有任務在等待執行,并且無法提交新任 務。
executorService.execute(new TestRunnable());
1、創建ExecutorService
通過工具類java.util.concurrent.Executors的靜態方法來創建。
Executors此包中所定義的 Executor、ExecutorService、ScheduledExecutorService、ThreadFactory 和 Callable 類的工廠和實用方法。
比如,創建一個ExecutorService的實例,ExecutorService實際上是一個線程池的管理工具:
ExecutorService executorService = Executors.newCachedThreadPool();
ExecutorService executorService = Executors.newFixedThreadPool(3);
ExecutorService executorService = Executors.newSingleThreadExecutor();
2、將任務添加到線程去執行
當將一個任務添加到線程池中的時候,線程池會為每個任務創建一個線程,該線程會在之后的某個時刻自動執行。
示例1:
@Test
public void testDemo() throws Exception {
//單例線程,任意時間(同一時間)池中只能有一個線程
ExecutorService es = Executors.newSingleThreadExecutor();
es.execute(new Runnable() {
@Override
public void run() {
System.err.println("線程啟動并運行"+Thread.currentThread().getName());
}
});
es.execute(new Runnable() {
@Override
public void run() {
System.err.println("第二個也運行了"+Thread.currentThread().getName());
}
});
//Thread.sleep(1000 * 60 * 60);
}
運行結果如下:兩個都會執行,但程序只會使用一個線程來運行。
線程啟動并運行pool-1-thread-1
第二個也運行了pool-1-thread-1
示例2:
@Test
public void testDemo3() throws Exception {
//聲明一個線程池
ExecutorService ex = Executors.newCachedThreadPool();
for (int i = 0; i < 4; i++) {
final int a = i;
//每一次execute方法,都是向池中放入一個對象
ex.execute(new Runnable() {
public void run() {
while(true){
System.err.println("測試...."+a+">"
+Thread.currentThread().getName()+","
+Thread.currentThread().isDaemon());
try{
Thread.sleep(2000);
}catch(Exception e){
e.printStackTrace();
}
}
}
});
}
Thread.sleep(1000*60*60);
}
輸出的結果如下:從中可以發現,第四個一組輸出,即一共創建了四個線程,每次每個線程都會執行輸出,但不按順序:位每一次輸出都四個算是一組
測試....0>pool-1-thread-1,false
測試....3>pool-1-thread-4,false
測試....2>pool-1-thread-3,false
測試....1>pool-1-thread-2,false
測試....0>pool-1-thread-1,false
測試....3>pool-1-thread-4,false
測試....2>pool-1-thread-3,false
測試....1>pool-1-thread-2,false
測試....1>pool-1-thread-2,false
測試....2>pool-1-thread-3,false
測試....3>pool-1-thread-4,false
測試....0>pool-1-thread-1,false
示例3:
public void testCall() throws Exception{
//聲明一個類,可以被調用,類似于線程,但它可以擁有返回值
class MyCall implements Callable<String>{
private int seq;
public MyCall(int seq){
this.seq=seq;
}
//拋出異常并可以擁有返回值
public String call() throws Exception {
System.err.println("執行"+seq+","+Thread.currentThread().getName());
Thread.sleep(3000);
System.err.println("Weak up "+seq);
return "完成"+seq;//這是返回值
}
}
ExecutorService es = Executors.newCachedThreadPool();//創建線程池對象
List<Future<String>> result =new ArrayList<Future<String>>();//放結果用的集合
for(int i=0;i<3;i++){
Future<String> f=es.submit(new MyCall(i));//線程執行完成以后可以通過引用獲取返回值
result.add(f);
}
for(Future<String> f:result){
System.err.println("返回值:"+f.get());//輸出返回的值
}
System.err.println("完成....");
}