多線程實現
一、多線程的四種實現方式
1.繼承Thread類(Thread實現Runnable接口)
2.實現Runnable接口
3.線程池
4.實現Callable接口
二、Callable的實現方式
首先, Java所有關於多線程的操作,都是Runnable的實現,但是Callable接口並沒有繼承Runnable接口,所以不能直接使用Callable實現多線程
通過查看JDK1.8文檔, 可以看到Runnable有許多實現類,其中一個是FutureTask的實現類
查看源碼,可以看到FutureTask類實現了RunnableFuture接口
RunnableFuture接口繼承了Runnable和Future接口
再看一下FutureTask實現類的構造方法
有兩個構造方法,第一個, 需要傳入Runnable的實現,不是我要的
第二個,傳入Callable接口的實現,通過這個構造方法,就可以通過實現Callable接口的方式實現多線程
Callable是一個函數式接口,只需要實現一個方法, call方法
三、Callable實現多線程Demo
創建一個ProjectPrice類模擬計算工程價格的業務, 實現Callable接口, 實現其中的call方法, 返回Integer類型數據
public class ProjectPrice implements Callable<Integer> {
private Integer price;
private String productName;
@Override
public Integer call() throws Exception {
if (productName.equals("材料")) {
TimeUnit.SECONDS.sleep(3);
System.out.println("正在計算材料價格");
price = 100;
}
if (productName.equals("人工")) {
TimeUnit.SECONDS.sleep(2);
System.out.println("正在計算人工價格");
price = 20;
}
return price;
}
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
}
測試類, 創建兩個線程,分別計算材料費和人工費
public class Test1 {
public static void main(String[] args) throws InterruptedException, ExecutionException {
System.out.println("開始覈算工程價格");
ProjectPrice projectPrice1 = new ProjectPrice();
projectPrice1.setProductName("人工");
//創建FutureTask,調用構造方法,傳入Callable實現類
FutureTask<Integer> futureTask1 = new FutureTask<Integer>(projectPrice1);
//創建線程,傳入FutureTask,開啓多線程
new Thread(futureTask1).start();
ProjectPrice projectPrice2 = new ProjectPrice();
projectPrice2.setProductName("材料");
FutureTask<Integer> futureTask2 = new FutureTask<Integer>(projectPrice2);
new Thread(futureTask2).start();
//通過FutureTask的get方法,獲取計算結果
Integer rengong = futureTask1.get();
Integer cailiao = futureTask2.get();
System.out.println("人工費用: " + rengong);
System.out.println("材料費用: " + cailiao);
System.out.println("共花費: " + (rengong + cailiao));
}
}
輸出結果:
開始覈算工程價格
正在計算人工價格
正在計算材料價格
人工費用: 20
材料費用: 100
共花費: 120
四、總結
1)不是說Java中多線程的實現都必須要實現Runnable接口嗎?爲什麼這裏只實現callable接口就可以了.
答: 在創建多線程的時候,傳入到Thread構造方法中的參數是FutureTask,而FutureTask實現了RunnableFuture接口,RunnableFuture接口繼承了Runnable接口,其實是間接實現了Runnable接口
2)Runnable接口必須要實現run方法,爲什麼沒有實現run方法也可以實現多線程?
答: 因爲FutureTask已經幫我們實現了run方法, 再run方法中, FutureTask會幫我們調用callable接口的call方法,所以只需要實現call方法即可
3)Runnable和Callable的區別
Runnable實現run方法,沒有返回值
Runable是java.lang包下的接口
Runnable是java原生的多線程頂端接口,可以直接實現多線程
Callable實現call方法
Callable是JUC包下的接口, 更高級的接口
Callable是另外的實現多線程的方式, 和多線程之間並沒有直接關係, 需要通過FutureTask中間類來實現多線程操作
Callable通過get方法獲取返回值的時候,會阻塞當前主線程,直到獲取到值後再繼續執行主線程
筆記有誤的話,請指出,謝謝