Java多線程——<四>讓線程有返回值

1、概述異步

  到目前爲止,咱們已經可以聲明並使一個線程任務運行起來了。可是遇到一個問題:如今定義的任務都沒有任何返回值,那麼加入咱們但願一個任務運行結束後告訴我一個結果,該結果表名任務執行成功或失敗,此時該怎麼辦呢?ide

  答案是使用Callable。以前定義的任務都直接實現了Runnable,該接口的run方法並沒有返回值。而Callable的call方法能夠根據你傳入的泛型參數返回對應類型的數據。函數

2、實現this

  1.實現Callable接口,定義可返回結果的線程任務spa

複製代碼
public class TaskCallable implements Callable<String>{
    private int id;
    public TaskCallable(int id){
        this.id = id;
    }
    @Override
    public String call() throws Exception {
        
        return "result of taskWithResult "+id;
    }
}
複製代碼

  注意,泛型參數String表示的是該任務執行以後返回結果的類型。.net

  2.將該任務交給線程執行者executor,讓他來代理執行這些線程線程

ExecutorService exec = Executors.newCachedThreadPool();//工頭
ArrayList<Future<String>> results = new ArrayList<Future<String>>();//
for(int i = 0 ; i < 10 ;i++){
    results.add(exec.submit(new TaskCallable(i)));//submit返回一個Future,表明了即將要返回的結果
}

  注意,此時須要使用executor的submit方法來調用Callable的call。代理

  該方法將返回一個Future接口的對象,它的泛型參數表明了call方法要返回的參數類型。code

  3.Future類型對象

  簡單的瞭解了下Future類型:按照名字判斷該類型對象表明了線程執行完成後的結果,因此叫Future。那麼在獲取該類型存放的線程運行結果時,可能該線程並未運行完畢,因此稱其爲「未來的結果」。

  •   首先,能夠用isDone()方法來查詢Future是否已經完成,任務完成後,能夠調用get()方法來獲取結果
  •     若是不加判斷直接調用get方法,此時若是線程未完成,get將阻塞,直至結果準備就緒

 

 

從線程中返回數據的兩種方法

一、經過類變量和類方法返回數據

二、經過回調函數返回數據

三、實現 Callable<V>接口,其中 V 表明 返回值類型


1、經過變量和方法返回數據

先看以下一段代碼

public class MyThread extends Thread
{
  private String value1;

  private String value2;


  public void run()
  {
  value1 = "value1";
  value2 = "value2";
  }

public static void main(String[] args)
{

MyThread t1 = new MyThread();
t1.start();
System.out.println(t1.value1);
System.out.println(t1.value2);
}


}

輸出結果 :

null
null
1
2
上面的運行結果很不正常,在run方法中已經對value1和value2進行賦值,可是返回倒是null。發生這種狀況的緣由是: 在調用strat()方法後就當即輸出 value1 和 value2 的值,而這裏的run 方法 尚未指定到value1 和 value2 賦值語句。

若是要避免這種狀況,就須要等run方法執行完成後才輸出 vaue1 和value2 代碼。能夠考慮使用sleep 將主線程進行延遲,可是有一個問題,你不知道須要延遲多久才能知道 value2 或 value1 有值 !!! 咱們能夠這樣作,以下代碼

public class MyThread extends Thread
{
private String value1;

private String value2;


public void run()
{
value1 = "value1";
value2 = "value2";
}

public static void main(String[] args) throws InterruptedException
{

MyThread t1 = new MyThread();
t1.start();

while(t1.value1 == null || t1.value1 == null)
{
sleep(100);
}
System.out.println(t1.value1);
System.out.println(t1.value2);
}


}

輸出結果:

value1
value2
1
2
以上方法雖然幫助咱們解決了問題,可是Java的線程模型爲咱們提供了更好的解決方案,就是使用join()方法,join()方法的功能 就是使線程 從異步執行 變成同步執行 。當線程變成同步執行後,就跟普通方法中獲得返回數據沒什麼區別了。

public static void main(String[] args) throws InterruptedException
{

MyThread t1 = new MyThread();
t1.start();
t1.join();
System.out.println(t1.value1);
System.out.println(t1.value2);
}

2、經過回調函數返回數據

跟 經過回調方法向線程傳遞 數據的 思路一致

3、實現 Callable 接口

一、定義任意類並實現 Callable 接口,並實現 方法 V call() throws Exception。其中,v 皆是表明返回值類型

二、在 V call() throws Exception 方法裏 定義 方法體,並 return 一個返回值

三、建立線程池,建立任務對象,線程池經過submit(任務對象) 執行任務,並返回一個 Future<V> 對象

四、經過Future對象.get() 方法獲取返回值

五、關閉線程池,釋放資源

public class MyThread implements Callable<String>
{

private String value;

public MyThread(String value)
{
this.value = value;
}

public String call() throws Exception
{

System.out.println(Thread.currentThread().getName());//pool-1-thread-1
return "線程返回值是:"+this.value;
}

public static void main(String[] args)
{

//建立一個線程池對象
ExecutorService pool = Executors.newCachedThreadPool();

//建立一個有返回值的任務
MyThread task = new MyThread("Java");

//執行任務並獲取Future對象
Future<String> future = pool.submit(task);

//從 Future 對象 獲取任務返回值
while(true)
{
//能夠用isDone()方法來查詢Future是否已經完成,任務完成後,能夠調用get()方法來獲取結果
//注意: 若是不加判斷直接調用get方法,此時若是線程未完成,get將阻塞,直至結果準備就緒
if(future.isDone())
{
try
{

String returnValue = future.get().toString();

System.out.println("線程返回值:"+returnValue);


}catch (Exception e){

e.printStackTrace();
}

//關閉線程池
pool.shutdown();

//跳出循環
break;
}


}

}

相關文章
相關標籤/搜索