1、Runnable和Callable的區別
(1) Callable規定的方法是 call(), Runnable規定的方法是 run()。
(2) Callable的任務執行后可返回值,而 Runnable的任務是不能返回值。
(3) call方法可以拋出異常, run方法不可以。
(4)運行 Callable任務可以拿到一個 Future對象
Future表示異步計算的結果。它提供了檢查計算是否完成的方法,以等待計算的完成,並獲取計算的結果。計算完成后只能使用 get方法來獲取結果,如果線程沒有執行完, Future.get()方法可能會阻塞當前線程的執行;如果線程出現異常, Future.get()會 throws InterruptedException或者 ExecutionException;如果線程已經取消,會跑出 CancellationException。取消由 cancel方法來執行。
isDone確定任務是正常完成還是被取消了。一旦計算完成,就不能再取消計算。如果為了可取消性而使用 Future但又不提供可用的結果,則可以聲明 Future <?> 形式類型、並返回null作為底層任務的結果。
Future接口的定義如下:
Future模式在請求發生時,會先產生一個 Future憑證給發出請求的客戶,它的作用就像是 Proxy物件,同時,由一個新的執行線程持續進行目標物件的生成( Thread - Per - Message),真正的目標物件生成之后,將之設定至 Future之中,而當客戶端真正需要目標物件時,目標物件也已經准備好,可以讓客戶提取使用。
結合 JDK的 Future來看,就是你 run線程后,你可以把線程的返回值賦給 Future並返回一個 Future對象。這時你可以立即拿到這個對象,然后進行下面的邏輯。但是如果你要 get這個 Future中的線程結果,就會被阻塞直到線程結束。
相當於現在的期房,你把手續和錢都交上去了,就可以馬上拿到合同,但只有合同沒有房子。這個時候你已經是有房一族了,你可以先去買家電買裝修(走下面的其他邏輯)。但是你要把家電和裝修放進去,就必須等到房子完工(阻塞)。
2、Callable實現:
submit方法會產生Future對象,它用Callable返回結果的特定類型進行了參數化,可以用isDone()的方法來查詢Future是否已經完成。當任務完成是,它具有一個結果,可以調用get()方法來獲取該結果。
package zeze;
import java.util.ArrayList;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
/***
*
* @ClassName: EbayMultiplyThreadCheck
* @Description: TODO
* @author zeze
* @date 2017年2月16日 上午8:49:46
*
*/
public class EbayMultiplyThreadCheck {
public static void main(String[] args) {
ExecutorService exec = Executors.newFixedThreadPool(10);
ArrayList<Future<String>> results = new ArrayList<Future<String>>();
for (int i = 0; i < 10; i++) {
String email = "asd" + i + "@qq.com";
results.add(exec.submit(new TaskWithResult(email)));
}
boolean isDone = false;
while (!isDone) {
isDone = true;
for (Future<String> future : results) {
if (!future.isDone()) {
isDone = false;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
break;
}
}
}
exec.shutdown();
}
}
class TaskWithResult implements Callable<String> {
private String email;
public TaskWithResult(String email) {
this.email = email;
}
@Override
public String call() {
System.out.println(email);
return null;
}
}
3、Runnable 實現
/**
* @Title: RunnableDemo.java
* @Package zeze
* @Description: TODO(用一句話描述該文件做什么)
* @author A18ccms A18ccms_gmail_com
* @date 2017年3月13日 下午4:08:09
* @version V1.0
*/
package zeze;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javafx.animation.Animation.Status;
/**
* @ClassName: RunnableDemo
* @Description: TODO
* @author zeze
* @date 2017年3月13日 下午4:08:09
*
*/
public class RunnableDemo implements Runnable {
protected int countDown = 10;
private static int taskCount = 0;
private final int id = taskCount++;
public RunnableDemo() {
}
public RunnableDemo(int countDown) {
this.countDown = countDown;
}
public String status() {
return "#" + id + "(" + (countDown > 0 ? countDown : "LiftOff!") + ").";
}
@Override
public void run() {
while (countDown-- > 0) {
System.out.print(status());
Thread.yield();// 將CPU從一個線程轉移給另一個線程
}
}
public static void main(String[] args) {
System.out.println("這個任務的run()不是單獨的線程驅動,是在main()中直接調用");
RunnableDemo launch = new RunnableDemo();
launch.run();
System.out.println();
System.out.println("************************************");
System.out.println("在新線程中啟動任務");
Thread thread = new Thread(new RunnableDemo());
thread.start();
System.out.println("Waiting for LiftOff");
System.out.println("************************************");
System.out.println("添加多個線程去驅動更多的任務");
for (int i = 0; i < 5; i++) {
new Thread(new RunnableDemo()).start();
}
System.out.println("Waiting for LiftOff");
System.out.println("************************************");
System.out.println("使用executor");
ExecutorService exec = Executors.newCachedThreadPool();
exec=Executors.newFixedThreadPool(5);
for (int i = 0; i < 5; i++) {
exec.execute(new RunnableDemo());
}
exec.shutdown();
}
}
