線程池提交任務時submit()和execute()的區別


因為之前一直是用的execute方法,最近有個情況需要用到submit方法,所以研究了下。

他們的區別:

1、execut()可以添加一個Runable任務,submit()不僅可以添加Runable任務還可以添加Callable任務。

2、execut()沒有返回值,而submit()在添加Callable任務時會有返回值(再添加Runable任務時也有,不過無意義),可以通過返回值來查看線程執行的情況。

3、如果發生異常submit()可以通過捕獲Future.get拋出的異常,而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、將任務添加到線程去執行

當將一個任務添加到線程池中的時候,線程池會為每個任務創建一個線程,該線程會在之后的某個時刻自動執行。

三、關閉執行服務對象

        executorService.shutdown();

 四、綜合實例

package concurrent; 
import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 
publicclass TestCachedThreadPool { publicstaticvoid 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 { publicvoid run() { System.out.println(Thread.currentThread().getName() + "線程被調用了。"); while (true) { try { Thread.sleep(5000); System.out.println(Thread.currentThread().getName()); } catch (InterruptedException e) { e.printStackTrace(); } } } }

 運行結果:

 ************* a0 ************* 
************* a1 ************* 
pool-1-thread-2線程被調用了。 
************* a2 ************* 
pool-1-thread-3線程被調用了。 
pool-1-thread-1線程被調用了。 
************* a3 ************* 
************* a4 ************* 
pool-1-thread-4線程被調用了。 
pool-1-thread-5線程被調用了。 
pool-1-thread-2 
pool-1-thread-1 
pool-1-thread-3 
pool-1-thread-5 
pool-1-thread-4 
pool-1-thread-2 
pool-1-thread-1 
pool-1-thread-3 
pool-1-thread-5 
pool-1-thread-4 
     ......

 五、獲取任務的執行的返回值

  在Java5之后,任務分兩類:一類是實現了Runnable接口的類,一類是實現了Callable接口的類。兩者都可以被ExecutorService執行,但是Runnable任務沒有返回值,而Callable任務有返回值。並且Callable的call()方法只能通過ExecutorService的submit(<T> task) 方法來執行,並且返回一個 <T>,是表示任務等待完成的 Future。
 
  Callable 接口類似於Runnable接口,兩者都是為那些其實例可能被另一個線程執行的類設計的。但是 Runnable 不會返回結果,並且無法拋出經過檢查的異常,但是Callable可以。Callable中的call()方法類似Runnable的run()方法,就是前者有返回值,后者沒有。

   當將一個Callable的對象傳遞給ExecutorService的submit方法,則該call方法自動在一個線程上執行,並且會返回執行結果Future對象。同樣,將Runnable的對象傳遞給ExecutorService的submit方法,則該run方法自動在一個線程上執行,並且會返回執行結果Future對象,但是在該Future對象上調用get方法,將返回null。

 下面看個例子:

import java.util.ArrayList; 
import java.util.List; 
import java.util.concurrent.*; 
/** 
* Callable接口測試 
*/
publicclass CallableDemo { 
    publicstaticvoid 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 { 
                 System.out.println(fs.get());     //打印各個線程(任務)執行的結果
            } catch (InterruptedException e) { 
                 e.printStackTrace(); 
            } catch (ExecutionException e) { 
                 e.printStackTrace(); 
            } finally { 
                 //啟動一次順序關閉,執行以前提交的任務,但不接受新任務。如果已經關閉,則調用沒有其他作用。
                 executorService.shutdown(); 
            } 
        } 
    } 
} 

class TaskWithResult implements Callable<String> { 
    privateint id; 
    public TaskWithResult(int id) { 
        this.id = id; 
    } 

    /** 
     * 任務的具體過程,一旦任務傳給ExecutorService的submit方法,則該方法自動在一個線程上執行。 
     * 
     * @return 
     * @throws Exception 
     */
    public String call() throws Exception { 
        System.out.println("call()方法被自動調用,干活!!!" + Thread.currentThread().getName()); 
        //一個模擬耗時的操作
        for (int i = 999999; i > 0; i--) ; 
        return"call()方法被自動調用,任務的結果是:" + id + "" + Thread.currentThread().getName(); 
    } 
}

 運行結果:

call()方法被自動調用,干活!!!             pool-1-thread-1 
call()方法被自動調用,干活!!!             pool-1-thread-3 
call()方法被自動調用,干活!!!             pool-1-thread-4 
call()方法被自動調用,干活!!!             pool-1-thread-6 
call()方法被自動調用,干活!!!             pool-1-thread-2 
call()方法被自動調用,干活!!!             pool-1-thread-5 
call()方法被自動調用,任務的結果是:0    pool-1-thread-1 
call()方法被自動調用,任務的結果是:1    pool-1-thread-2 
call()方法被自動調用,干活!!!             pool-1-thread-2 
call()方法被自動調用,干活!!!             pool-1-thread-6 
call()方法被自動調用,干活!!!             pool-1-thread-4 
call()方法被自動調用,任務的結果是:2    pool-1-thread-3 
call()方法被自動調用,干活!!!             pool-1-thread-3 
call()方法被自動調用,任務的結果是:3    pool-1-thread-4 
call()方法被自動調用,任務的結果是:4    pool-1-thread-5 
call()方法被自動調用,任務的結果是:5    pool-1-thread-6 
call()方法被自動調用,任務的結果是:6    pool-1-thread-2 
call()方法被自動調用,任務的結果是:7    pool-1-thread-6 
call()方法被自動調用,任務的結果是:8    pool-1-thread-4 
call()方法被自動調用,任務的結果是:9    pool-1-thread-3 

Process finished with exit code 0

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM