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