最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java中Runnable和Callable分別什么時(shí)候使用

 更新時(shí)間:2023年08月07日 15:03:26   作者:古時(shí)的風(fēng)箏  
提到 Java 就不得不說多線程了,就算你不想說,面試官也得讓你說呀,那說到線程,就不得不說Runnable和Callable這兩個(gè)家伙了,二者在什么時(shí)候使用呢,下面就來和簡(jiǎn)單講講

提到 Java 就不得不說多線程了,就算你不想說,面試官也得讓你說呀,對(duì)不對(duì)。那說到多線程,就不得提線程了(這不廢話嗎)。那說到線程,就不得不說RunnableCallable這兩個(gè)家伙了。

說熟悉也是真熟悉,在剛學(xué)習(xí)多線程的時(shí)候,第一個(gè)例子大概就是下面這樣子的。

new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("執(zhí)行線程" + Thread.currentThread().getName());
    }
}).start();

看到了 Runnable的身影,有時(shí)候還會(huì)看到Callable的。

但是說很熟悉吧,印象也不是很大,好像就用了一下這兩位的名號(hào),然后剩下的部分就跟他倆沒啥關(guān)系了。

今天,我們就來看看這兩位到底是什么,有什么區(qū)別,什時(shí)候應(yīng)該用 Runnable,什么時(shí)候又應(yīng)該用 Callable。

Runnable

自從Java誕生,Runnable就存在了,元老中的元老了,在 1.5之前,如果你想使用線程,那必須要實(shí)現(xiàn)自 Runnable。因?yàn)榈搅?JDK1.5,JDK 才加入了Callable。

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

是不是接口非常簡(jiǎn)單,就一個(gè)抽象方法。

其實(shí)還可以再簡(jiǎn)化一下, @FunctionalInterface標(biāo)明這個(gè)接口是一個(gè)函數(shù)式接口。函數(shù)式接口是在 JDK8才加入的,為的就是實(shí)現(xiàn)函數(shù)式編程,就那種Lambada表達(dá)式。

所以在 JDK1.7中,是沒有@FunctionalInterface修飾的,簡(jiǎn)簡(jiǎn)單單。我們找到 JDK1.7的 Ruunable實(shí)現(xiàn),是下面這樣子

public interface Runnable {
    public abstract void run();
}

想了解更多函數(shù)式編程的話,可以看這篇文章:Lambda、函數(shù)式接口、Stream 一次性全給你

如果一個(gè)線程類要實(shí)現(xiàn) Runnable 接口,則這個(gè)類必須定義一個(gè)名為 run 的無參數(shù)方法。

實(shí)現(xiàn)了 Runnable 接口的類可以通過實(shí)例化一個(gè) Thread 實(shí)例,并將自身作為目標(biāo)傳遞來運(yùn)行。

舉個(gè)例子

首先定義一個(gè)RunnableThread類,并實(shí)現(xiàn)自(implements)Runnable接口,然后重寫 run方法。

public class RunnableThread implements Runnable{
    @Override
    public void run() {
        System.out.println("當(dāng)前線程名稱"+ Thread.currentThread().getName());
    }
}

使用RunnableThread作為線程類(Thread)實(shí)例化的參數(shù),然后調(diào)用run方法。

RunnableThread runnableThread = new RunnableThread();
Thread thread = new Thread(runnableThread);
thread.start();

注意,是調(diào)用新 new 出來的 Thread 實(shí)例的start() 方法,不要調(diào)用run方法,雖然我們是重寫Runnablerun方法的。調(diào)用 run方法并沒有創(chuàng)建線程的效果,而是直接在當(dāng)前線程執(zhí)行,就和執(zhí)行一個(gè)普通類的普通方法一模一樣。

為什么要調(diào)用 start()方法呢,我們看看 Threadstart()方法實(shí)現(xiàn)中,其實(shí)是調(diào)用了一個(gè)名稱為 start0()的 native 方法,native 方法就不是用 Java 實(shí)現(xiàn)的了,而是在 JVM 層面的實(shí)現(xiàn)。

這個(gè)start0方法的主要邏輯就是啟動(dòng)一個(gè)操作系統(tǒng)線程,并和 JVM 線程綁定,開辟一些空間來存儲(chǔ)線程狀態(tài)和上下文的數(shù)據(jù),然后執(zhí)行綁定的 JVM 線程(也就是我們實(shí)現(xiàn)了Runnable的類)的 run方法的代碼塊,從而執(zhí)行我們自定義的邏輯。

還可以用線程池的方式調(diào)用

ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()
        .setNameFormat("thread-pool-%d").build();
ExecutorService singleThreadPool = new ThreadPoolExecutor(1, 1,
        0L, TimeUnit.MILLISECONDS,
        new LinkedBlockingQueue<Runnable>(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());
singleThreadPool.execute(runnableThread);
singleThreadPool.shutdown();

如果 Runnable那么完美的話,就沒必要在 JDK1.5中加入和它超級(jí)相似的 Callable了。

Runnable有什么不完美的地方嗎?就是它的 run方法是沒有返回值的。

如果你想在主線程中拿到新開啟線程的返回值的話,Runnable就不太方便了。必須要借助共享變量來完成。

所以,如果你的場(chǎng)景是要有返回值的話, 就要 Callable出手了。

Callable

Callable是在 JDK1.5才加入的,為的就是彌補(bǔ) Runnable沒有返回值的缺陷,雖然絕大多數(shù)場(chǎng)景都可以用 Runnable來實(shí)現(xiàn)。

@FunctionalInterface
public interface Callable<V> {
    V call() throws Exception;
}

Runnable類似的,@FunctionalInterface也是后來加入的,可以不考慮,只是為了函數(shù)式寫法。

Callable接口只有一個(gè) call方法,并且有一個(gè)泛型返回值,可以返回任何類型。

舉個(gè)例子

首先聲明一個(gè)類,實(shí)現(xiàn)自 Callable接口,返回值為字符串類型

public class CallableThread implements Callable<String> {
    @Override
    public String call() throws Exception {
        return "線程名稱:" + Thread.currentThread().getName();
    }
}

在代碼中通過下面的方式調(diào)用

CallableThread callableThread = new CallableThread();
FutureTask<String> futureTask = new FutureTask<>(callableThread);
Thread thread = new Thread(futureTask);
thread.start();
String result = futureTask.get();
System.out.println("執(zhí)行結(jié)果= " + result);

看上去就比 Runnable要復(fù)雜一點(diǎn),要借助FutureTask了,因?yàn)?Thread類沒有接受Callable的構(gòu)造函數(shù)。

使用 FutureTask.get()方法獲取執(zhí)行結(jié)果。

在日常的開發(fā)中,不建議直接這樣用,除非你明確的知道這樣做沒有問題,否則的話,推薦使用線程池的方式來使用。

CallableThread callableThread = new CallableThread();
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<String> future = executor.submit(callableThread);
String result = future.get();
System.out.println("任務(wù)執(zhí)行結(jié)果: " + result);
executor.shutdown();

如何選擇用哪一個(gè)

取舍的基本原則就是需不需要返回值,如果不需要返回值,那直接就選 Runnable,不用猶豫。如果有返回值的話,那更不用猶豫,不要想著借助共享變量的方式。

另外還有一點(diǎn)就是是否需要拋出異常, Runnable是不接受拋出異常的,Callable可以拋出異常。

Runnable適合那種純異步的處理邏輯。比如每天定時(shí)計(jì)算報(bào)表,將報(bào)表存儲(chǔ)到數(shù)據(jù)庫(kù)或者其他地方,只是要計(jì)算,不需要馬上展示,展示內(nèi)容是在其他的方法中單獨(dú)獲取的。

比如那些非核心的功能,當(dāng)核心流程執(zhí)行完畢后,非核心功能就自己去執(zhí)行吧,至于成不成功的,不是特別重要。例如一個(gè)購(gòu)物下單流程,下單、減庫(kù)存、加到用戶的訂單列表、扣款是核心功能,之后的發(fā)送APP通知、短信通知這些就啟動(dòng)新線程去干去吧。

最后

Runnablejava.lang這個(gè)包下,而當(dāng)JDK1.5發(fā)布的時(shí)候,新加入的 Callable被安置在了 java.util.concurrent這個(gè)包下,這是 Java 里有名的并發(fā)編程相關(guān)包,各種鎖啊、多線程工具類啊,都被放在這個(gè)包下。按道理,Runnable 也應(yīng)該在這里才對(duì)。

可見再厲害的項(xiàng)目也是隨著項(xiàng)目的擴(kuò)大而慢慢的規(guī)劃,而前期的一些看似不太合理的地方,只能做兼容和妥協(xié)。

到此這篇關(guān)于Java中Runnable和Callable分別什么時(shí)候使用的文章就介紹到這了,更多相關(guān)Java Runnable Callable內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java實(shí)現(xiàn)樹形菜單的方法總結(jié)

    Java實(shí)現(xiàn)樹形菜單的方法總結(jié)

    當(dāng)我們想要展示層級(jí)結(jié)構(gòu),如文件目錄、組織結(jié)構(gòu)或分類目錄時(shí),樹形菜單是一個(gè)直觀且有效的解決方案,本文為大家整理了java中幾種常見方法,希望對(duì)大家有所幫助
    2023-08-08
  • 手把手教你實(shí)現(xiàn)Java第三方應(yīng)用登錄

    手把手教你實(shí)現(xiàn)Java第三方應(yīng)用登錄

    本文主要介紹了手把手教你實(shí)現(xiàn)Java第三方應(yīng)用登錄,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • 詳細(xì)聊一聊Java中的包機(jī)制

    詳細(xì)聊一聊Java中的包機(jī)制

    這篇文章主要介紹了Java中包機(jī)制的相關(guān)資料,Java包機(jī)制通過定義、命名和組織類,防止命名沖突,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2025-05-05
  • IDEA的TODO的使用方式

    IDEA的TODO的使用方式

    這篇文章主要介紹了IDEA的TODO的使用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • SpringBoot集成SpringSecurity和JWT做登陸鑒權(quán)的實(shí)現(xiàn)

    SpringBoot集成SpringSecurity和JWT做登陸鑒權(quán)的實(shí)現(xiàn)

    這篇文章主要介紹了SpringBoot集成SpringSecurity和JWT做登陸鑒權(quán)的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-04-04
  • Java面試必備八股文整理

    Java面試必備八股文整理

    這篇文章主要介紹了Java面試必備八股文整理,小伙伴們出去面試的時(shí)候會(huì)被問到很多java專業(yè)性的知識(shí),那么八股文就是為此而出現(xiàn)的,需要的朋友可以參考下
    2023-03-03
  • Java8如何將Array轉(zhuǎn)換為Stream的實(shí)現(xiàn)代碼

    Java8如何將Array轉(zhuǎn)換為Stream的實(shí)現(xiàn)代碼

    這篇文章主要介紹了Java8如何將Array轉(zhuǎn)換為Stream的實(shí)現(xiàn)代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09
  • 結(jié)合Mybatis聊聊對(duì)SQL注入的見解

    結(jié)合Mybatis聊聊對(duì)SQL注入的見解

    這篇文章主要介紹了結(jié)合Mybatis聊聊對(duì)SQL注入的見解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • java對(duì)象初始化代碼詳解

    java對(duì)象初始化代碼詳解

    這篇文章主要介紹了java對(duì)象初始化代碼詳解,涉及實(shí)例變量的初始化,類變量的初始化等相關(guān)介紹幾代碼示例,具有一定參考價(jià)值,需要的朋友可以了解下。
    2017-11-11
  • java 中 zookeeper簡(jiǎn)單使用

    java 中 zookeeper簡(jiǎn)單使用

    ZooKeeper是一個(gè)分布式的,開放源碼的分布式應(yīng)用程序協(xié)調(diào)服務(wù),是Google的Chubby一個(gè)開源的實(shí)現(xiàn),是Hadoop和Hbase的重要組件。下面通過本文給大家分享java 中 zookeeper簡(jiǎn)單使用,需要的朋友參考下吧
    2017-09-09

最新評(píng)論

中山市| 新龙县| 曲阜市| 封丘县| 延吉市| 辽中县| 青铜峡市| 咸阳市| 磴口县| 隆子县| 临沭县| 怀远县| 富川| 涟水县| 桃源县| 玉门市| 芦山县| 聂拉木县| 东兴市| 绵阳市| 大埔县| 重庆市| 寿阳县| 黄山市| 灵山县| 海丰县| 长葛市| 婺源县| 梨树县| 六盘水市| 涿鹿县| 囊谦县| 合川市| 苏尼特左旗| 连平县| 山阴县| 汶川县| 涞水县| 德州市| 陆良县| 米泉市|