Callable,Runnable的區別及用法

編寫多線程程序一般有三種方法,Thread,Runnable,Callable.

Runnable和Callable的區別是:

(1)Callable規定的方法是call(),Runnable規定的方法是run()。其中Runnable可以提交給Thread來包裝下,直接啓動一個線程來執行,而Callable則一般都是提交給ExecuteService來執行。
(2)Callable的任務執行後可返回值,而Runnable的任務是不能返回值得
(3)call方法可以拋出異常,run方法不可以
(4)運行Callable任務可以拿到一個Future對象,c表示異步計算的結果。

Future 提供了檢查計算是否完成的方法,以等待計算的完成,並獲取計算的結果。計算完成後只能使用 get 方法來獲取結果,如果線程沒有執行完,Future.get()方法可能會阻塞當前線程的執行;如果線程出現異常,Future.get()會throws InterruptedException或者ExecutionException;如果線程已經取消,會跑出CancellationException。取消由cancel 方法來執行。isDone確定任務是正常完成還是被取消了。一旦計算完成,就不能再取消計算。如果爲了可取消性而使用 Future 但又不提供可用的結果,則可以聲明Future<?> 形式類型,並返回 null 作爲底層任務的結果。

/**

  • 通過簡單的測試程序來試驗Runnable、Callable通過Executor來調度的時候與Future的關係
    */
    package com.hadoop.thread;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class RunnableAndCallable2Future {

public static void main(String[] args) {

    // 創建一個執行任務的服務
    ExecutorService executor = Executors.newFixedThreadPool(3);
    try {
        //1.Runnable通過Future返回結果爲空
        //創建一個Runnable,來調度,等待任務執行完畢,取得返回結果
        Future<?> runnable1 = executor.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println("runnable1 running.");
            }
        });
        System.out.println("Runnable1:" + runnable1.get());

        // 2.Callable通過Future能返回結果
        //提交併執行任務,任務啓動時返回了一個 Future對象,
        // 如果想得到任務執行的結果或者是異常可對這個Future對象進行操作
        Future<String> future1 = executor.submit(new Callable<String>() {
            @Override
            public String call() throws Exception {
                // TODO Auto-generated method stub
                return "result=task1";
            }
        });
        // 獲得任務的結果,如果調用get方法,當前線程會等待任務執行完畢後才往下執行
        System.out.println("task1: " + future1.get());

        //3. 對Callable調用cancel可以對對該任務進行中斷
        //提交併執行任務,任務啓動時返回了一個 Future對象,
        // 如果想得到任務執行的結果或者是異常可對這個Future對象進行操作
        Future<String> future2 = executor.submit(new Callable<String>() {
            @Override
            public String call() throws Exception {             
                try {
                    while (true) {
                        System.out.println("task2 running.");
                        Thread.sleep(50);
                    }
                } catch (InterruptedException e) {
                    System.out.println("Interrupted task2.");
                }
                return "task2=false";
            }
        });

        // 等待5秒後,再停止第二個任務。因爲第二個任務進行的是無限循環
        Thread.sleep(10);
        System.out.println("task2 cancel: " + future2.cancel(true));

        // 4.用Callable時拋出異常則Future什麼也取不到了
        // 獲取第三個任務的輸出,因爲執行第三個任務會引起異常
        // 所以下面的語句將引起異常的拋出
        Future<String> future3 = executor.submit(new Callable<String>() {

            @Override
            public String call() throws Exception {
                throw new Exception("task3 throw exception!");
            }

        });
        System.out.println("task3: " + future3.get());
    } catch (Exception e) {
        System.out.println(e.toString());
    }
    // 停止任務執行服務
    executor.shutdownNow();
}

}

執行結果如下:

runnable1 running.
Runnable1:null
task1: result=task1
task2 running.
task2 cancel: true
Interrupted task2.
java.util.concurrent.ExecutionException: java.lang.Exception: Bad flag value!

FutureTask則是一個RunnableFuture,即實現了Runnbale又實現了Futrue這兩個接口,另外它還可以包裝Runnable和Callable,所以一般來講是一個符合體了,它可以通過Thread包裝來直接執行,也可以提交給ExecuteService來執行,並且還可以通過v get()返回執行結果,在線程體沒有執行完成的時候,主線程一直阻塞等待,執行完則直接返回結果。

public class FutureTaskTest {

/**
 * @param args
 */
public static void main(String[] args) {
    Callable<String> task = new Callable<String>() {
        public String call() {
            System.out.println("Sleep start.");
            try {
                Thread.sleep(1000 * 10);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println("Sleep end.");
            return "time=" + System.currentTimeMillis();
        }
    };

    //直接使用Thread的方式執行
    FutureTask<String> ft = new FutureTask<String>(task);
    Thread t = new Thread(ft);
    t.start();
    try {
        System.out.println("waiting execute result");
        System.out.println("result = " + ft.get());
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (ExecutionException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    //使用Executors來執行
    System.out.println("=========");
    FutureTask<String> ft2 = new FutureTask<String>(task);
    Executors.newSingleThreadExecutor().submit(ft2);
    try {
        System.out.println("waiting execute result");
        System.out.println("result = " + ft2.get());
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (ExecutionException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

}

}

執行結果如下:

waiting execute result
Sleep start.
Sleep end.
result = time=1370844662537

waiting execute result
Sleep start.
Sleep end.
result = time=1370844672542

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章