国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專(zhuān)欄INFORMATION COLUMN

Java 多線程(1):獲得線程的返回結(jié)果

VincentFF / 3095人閱讀

摘要:使用獲得返回結(jié)果新建個(gè)線程,每個(gè)線程分別負(fù)責(zé)累加慢速累加器線程等待線程執(zhí)行完畢累加的結(jié)果運(yùn)行結(jié)束,結(jié)果為運(yùn)行結(jié)果第二種方法使用和。

Java 對(duì)多線程編程提供了內(nèi)置的支持并提供了良好的 API,通過(guò)使用 ThreadRunnable 兩個(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 接口,Threadrun 方法的實(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 的代碼:

Runnablerun 方法是不帶返回值的,那如果我們需要一個(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é)果:");

        List workers = 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é)果:

第二種方法:使用 CallableFutureTask
Callable 是 JDK1.5 時(shí)添加的類(lèi),為的就是解決 Runnable 的痛點(diǎn)(沒(méi)有返回值不能拋出異常)。

Callable.java 的代碼:

可以看到參數(shù)化類(lèi)型 V 就是返回的值的類(lèi)型。

但是查看 Thread 的構(gòu)造方法,我們發(fā)現(xiàn) Thread 只提供了將 Runnable 作為參數(shù)的構(gòu)造方法,并沒(méi)有使用 Callable 的構(gòu)造方法 —— 所以引出 FutureTask

FutureTask 也是 JDK1.5 時(shí)添加的類(lèi),查看它的類(lèi)聲明:

可以看到它實(shí)現(xiàn)了 RunnableFuture 這個(gè)接口,我們?cè)倏纯?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 通過(guò) RunnableFuture 實(shí)現(xiàn)的第二個(gè)接口:Future
(事實(shí)上,RunnableFuture 是在 JDK1.6 時(shí)添加的類(lèi),我猜測(cè)在 JDK1.5 時(shí) FutureTask 應(yīng)該是直接實(shí)現(xiàn)的 RunnableFuture,而不是通過(guò) RunnableFuture

Future.java 的源碼:

Future 包含的方法有 5 個(gè),本文只關(guān)注它兩個(gè) get 相關(guān)的方法。通過(guò) Java 的 API 文檔,我們可以知道 get 方法是用來(lái)返回和 Future 關(guān)聯(lián)的任務(wù)的結(jié)果(即構(gòu)造 FutureTask 時(shí)使用的 Callable 的結(jié)果)。帶參數(shù)的 get 方法指定一個(gè)超時(shí)時(shí)間,在超時(shí)時(shí)間內(nèi)該方法會(huì)阻塞當(dāng)前線程,直到獲得結(jié)果之后停止阻塞繼續(xù)運(yùn)行 —— 如果在給定的超時(shí)時(shí)間內(nèi)沒(méi)有獲得結(jié)果,那么便拋出 TimeoutException 異常;不帶參數(shù)的 get 可以理解為超時(shí)時(shí)間無(wú)限大,即一直等待直到獲得結(jié)果。

Future 每個(gè)方法的詳細(xì)用法可以參考 Java 多線程(3))

通過(guò)以上我們可以知道,CallableFutureFutureTask 這三個(gè)類(lèi)是相輔相成的。以上提到關(guān)鍵類(lèi)的類(lèi)關(guān)系如下:

現(xiàn)在我們看看 FutureTask 中實(shí)現(xiàn) Runnablerun 方法是怎樣的(我們直接看關(guān)鍵代碼):

代碼的意思很明確,調(diào)用構(gòu)造 FutureTask 時(shí)傳入的 Callablecall 方法,如果正常執(zhí)行完畢,那么通過(guò) set(result) 設(shè)置結(jié)果,通過(guò) get() 方法得到的即為這個(gè)結(jié)果 —— 思路和前面第一種方法是一致的(當(dāng)然 FutureTask 是更強(qiáng)大和更通用的類(lèi));否則即為拋出異常的情況。

使用 FutureTask 的過(guò)程如下:
(1)通過(guò)一個(gè) Callable 任務(wù)或者一個(gè) Runnable(一開(kāi)始就指定 result)任務(wù)構(gòu)造 FutureTask
(2)將 FutureTask 交給 Thread 去運(yùn)行;
(3)使用 FutureTaskget 方法(或者 Threadjoin 方法)阻塞當(dāng)前線程直到獲得任務(wù)的結(jié)果。

現(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 + FutureTask 的程序代碼要比 Runnable 的代碼更簡(jiǎn)潔和方便 —— 當(dāng)需要線程執(zhí)行完成返回結(jié)果時(shí)(或者任務(wù)需要拋出異常),Callable 是優(yōu)先于 Runnable 的選擇。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/66355.html

相關(guān)文章

  • Java線程學(xué)習(xí)(六)Lock鎖使用

    摘要:返回與此鎖相關(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)鍵字 ...

    Caicloud 評(píng)論0 收藏0
  • Java線程(2):使用線程池 ThreadPoolExecutor

    摘要:本文只介紹中線程池的基本使用,不會(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)存都...

    darry 評(píng)論0 收藏0
  • Java 線程(5):Fork/Join 型線程池與 Work-Stealing 算法

    摘要:時(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...

    IamDLY 評(píng)論0 收藏0
  • bat等大公司常考java線程面試題

    摘要:典型地,和被用在等待另一個(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)存單元...

    Charlie_Jade 評(píng)論0 收藏0
  • Java線程Java線程執(zhí)行框架

    摘要:線程執(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...

    silencezwm 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<