摘要:使用獲得返回結(jié)果新建個線程,每個線程分別負責累加慢速累加器線程等待線程執(zhí)行完畢累加的結(jié)果運行結(jié)束,結(jié)果為運行結(jié)果第二種方法使用和。
Java 對多線程編程提供了內(nèi)置的支持并提供了良好的 API,通過使用 Thread 和 Runnable 兩個基礎類,我們可以很方便的創(chuàng)建一個線程:
Runnable runnable = new Runnable() { @Override public void run() { System.out.println("線程啟動"); // 耗時操作 System.out.println("線程結(jié)束"); } }; Thread thread = new Thread(runnable); // 創(chuàng)建線程,runnable 作為線程要執(zhí)行的任務(載體) thread.start(); // 啟動線程 thread.join(); // 等待線程執(zhí)行完畢
{ 題外話開始:
通過 Thread 的類聲明:
我們可以知道 Thread 自己也實現(xiàn)了 Runnable 接口,Thread 中 run 方法的實現(xiàn)如下(Thread 啟動之后運行的就是 Thread 中的 run 方法):
(target 即構(gòu)造 Thread 時可傳入的 Runnable 對象,不傳入即為 null —— 所以繼承 Thread 重寫其 run 方法也是一種創(chuàng)建線程的方式)
題外話結(jié)束 }
Runnable.java 的代碼:
Runnable 的 run 方法是不帶返回值的,那如果我們需要一個耗時任務在執(zhí)行完之后給予返回值,應該怎么做呢?
第一種方法:在 Runnable 的實現(xiàn)類中設置一個變量 V,在 run 方法中將其改變?yōu)槲覀兤诖慕Y(jié)果,然后通過一個 getV() 方法將這個變量返回。
import java.util.*; public class RunnableTest { public static void main(String[] args) throws Exception { System.out.println("使用 Runnable 獲得返回結(jié)果:"); Listworkers = new ArrayList<>(10); List tasks = new ArrayList<>(10); // 新建 10 個線程,每個線程分別負責累加 1~10, 11~20, ..., 91~100 for (int i = 0; i < 10; i++) { AccumRunnable task = new AccumRunnable(i * 10 + 1, (i + 1) * 10); Thread worker = new Thread(task, "慢速累加器線程" + i); tasks.add(task); workers.add(worker); worker.start(); } int total = 0; for (int i = 0, s = workers.size(); i < s; i++) { workers.get(i).join(); // 等待線程執(zhí)行完畢 total += tasks.get(i).getResult(); } System.out.println(" 累加的結(jié)果: " + total); } static final class AccumRunnable implements Runnable { private final int begin; private final int end; private int result; public AccumRunnable(int begin, int end) { this.begin = begin; this.end = end; } @Override public void run() { result = 0; try { for (int i = begin; i <= end; i++) { result += i; Thread.sleep(100); } } catch (InterruptedException ex) { ex.printStackTrace(System.err); } System.out.printf("(%s) - 運行結(jié)束,結(jié)果為 %d ", Thread.currentThread().getName(), result); } public int getResult() { return result; } } }
運行結(jié)果:
第二種方法:使用 Callable
Callable
Callable.java 的代碼:
可以看到參數(shù)化類型 V 就是返回的值的類型。
但是查看 Thread 的構(gòu)造方法,我們發(fā)現(xiàn) Thread 只提供了將 Runnable 作為參數(shù)的構(gòu)造方法,并沒有使用 Callable
FutureTask
可以看到它實現(xiàn)了 RunnableFuture
可以看到 RunnableFuture 接口繼承了 Runnable 接口,那么 RunnableFuture 接口的實現(xiàn)類 FutureTask 必然會去實現(xiàn) Runnable 接口 —— 所以 FutureTask 可以用來當 Runnable 使用。查看 FutureTask 的構(gòu)造方法,發(fā)現(xiàn) FutureTask 有兩個構(gòu)造方法:
第一個構(gòu)造方法表明我們可以通過一個 Callable 去構(gòu)造一個 FutureTask —— 而 FutureTask 實現(xiàn)了 Runnable 接口,從而可以將該任務傳遞給 Thread 去運行;
第二個構(gòu)造方法是通過一個 Runnable 和一個指定的 result 去構(gòu)造 FutureTask。
我們再來看看 FutureTask
(事實上,RunnableFuture
Future.java 的源碼:
Future
(Future 每個方法的詳細用法可以參考 Java 多線程(3))
通過以上我們可以知道,Callable
現(xiàn)在我們看看 FutureTask 中實現(xiàn) Runnable 的 run 方法是怎樣的(我們直接看關鍵代碼):
代碼的意思很明確,調(diào)用構(gòu)造 FutureTask
使用 FutureTask
(1)通過一個 Callable
(2)將 FutureTask
(3)使用 FutureTask
現(xiàn)在我們使用 Callable 改寫程序:
import java.util.*; import java.util.concurrent.*; public class CallableTest { public static void main(String[] args) throws Exception { System.out.println("使用 Callable 獲得返回結(jié)果:"); List> futureTasks = new ArrayList<>(10); // 新建 10 個線程,每個線程分別負責累加 1~10, 11~20, ..., 91~100 for (int i = 0; i < 10; i++) { AccumCallable task = new AccumCallable(i * 10 + 1, (i + 1) * 10); FutureTask futureTask = new FutureTask<>(task); futureTasks.add(futureTask); Thread worker = new Thread(futureTask, "慢速累加器線程" + i); worker.start(); } int total = 0; for (FutureTask futureTask : futureTasks) { total += futureTask.get(); // get() 方法會阻塞直到獲得結(jié)果 } System.out.println("累加的結(jié)果: " + total); } static final class AccumCallable implements Callable { private final int begin; private final int end; public AccumCallable(int begin, int end) { this.begin = begin; this.end = end; } @Override public Integer call() throws Exception { int result = 0; for (int i = begin; i <= end; i++) { result += i; Thread.sleep(100); } System.out.printf("(%s) - 運行結(jié)束,結(jié)果為 %d ", Thread.currentThread().getName(), result); return result; } } }
運行結(jié)果:
可以看到使用 Callable
文章版權歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/66355.html
摘要:返回與此鎖相關聯(lián)的給定條件等待的線程數(shù)的估計。查詢是否有線程正在等待獲取此鎖。為公平鎖,為非公平鎖線程運行了獲得鎖定運行結(jié)果公平鎖的運行結(jié)果是有序的。 系列文章傳送門: Java多線程學習(一)Java多線程入門 Java多線程學習(二)synchronized關鍵字(1) java多線程學習(二)synchronized關鍵字(2) Java多線程學習(三)volatile關鍵字 ...
摘要:本文只介紹中線程池的基本使用,不會過多的涉及到線程池的原理??删彺婢€程的線程池創(chuàng)建一個可緩存線程的線程池。首先是從接口繼承到的方法使用該方法即將一個任務交給線程池去執(zhí)行。方法方法的作用是向線程池發(fā)送關閉的指令。 首先,我們?yōu)槭裁葱枰€程池?讓我們先來了解下什么是 對象池 技術。某些對象(比如線程,數(shù)據(jù)庫連接等),它們創(chuàng)建的代價是非常大的 —— 相比于一般對象,它們創(chuàng)建消耗的時間和內(nèi)存都...
摘要:時,標準類庫添加了,作為對型線程池的實現(xiàn)。類圖用來專門定義型任務完成將大任務分割為小任務以及合并結(jié)果的工作。 JDK 1.7 時,標準類庫添加了 ForkJoinPool,作為對 Fork/Join 型線程池的實現(xiàn)。Fork 在英文中有 分叉 的意思,而 Join 有 合并 的意思。ForkJoinPool 的功能也是如此:Fork 將大任務分叉為多個小任務,然后讓小任務執(zhí)行,Join...
摘要:典型地,和被用在等待另一個線程產(chǎn)生的結(jié)果的情形測試發(fā)現(xiàn)結(jié)果還沒有產(chǎn)生后,讓線程阻塞,另一個線程產(chǎn)生了結(jié)果后,調(diào)用使其恢復。使當前線程放棄當前已經(jīng)分得的時間,但不使當前線程阻塞,即線程仍處于可執(zhí)行狀態(tài),隨時可能再次分得時間。 1、說說進程,線程,協(xié)程之間的區(qū)別 簡而言之,進程是程序運行和資源分配的基本單位,一個程序至少有一個進程,一個進程至少有一個線程.進程在執(zhí)行過程中擁有獨立的內(nèi)存單元...
摘要:線程執(zhí)行框架啟動線程將要多線程執(zhí)行的任務封裝為一個對象將其傳給一個執(zhí)行框架對象從線程池中選擇線程執(zhí)行工作任務。 為什么需要執(zhí)行框架呢?使用一般的new方法來創(chuàng)建線程有什么問題呢?一般的new線程的方式一般要給出一個實現(xiàn)了Runnable接口的執(zhí)行類,在其中重寫run()方法,然后再在將這個執(zhí)行類的對象傳給線程以完成初始化,這個過程中線程的定義和執(zhí)行過程其實是雜糅在一起了,而且每次new...
閱讀 777·2023-04-25 15:13
閱讀 1399·2021-11-22 12:03
閱讀 826·2021-11-19 09:40
閱讀 1910·2021-11-17 09:38
閱讀 1714·2021-11-08 13:18
閱讀 655·2021-09-02 15:15
閱讀 1768·2019-08-30 15:54
閱讀 2636·2019-08-30 11:12