欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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ù)庫或者其他地方,只是要計(jì)算,不需要馬上展示,展示內(nèi)容是在其他的方法中單獨(dú)獲取的。

比如那些非核心的功能,當(dāng)核心流程執(zhí)行完畢后,非核心功能就自己去執(zhí)行吧,至于成不成功的,不是特別重要。例如一個(gè)購物下單流程,下單、減庫存、加到用戶的訂單列表、扣款是核心功能,之后的發(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)文章

  • SpringBoot中使用EasyExcel并行導(dǎo)出多個(gè)excel文件并壓縮zip后下載的代碼詳解

    SpringBoot中使用EasyExcel并行導(dǎo)出多個(gè)excel文件并壓縮zip后下載的代碼詳解

    SpringBoot的同步導(dǎo)出方式中,服務(wù)器會(huì)阻塞直到Excel文件生成完畢,在處理大量數(shù)據(jù)的導(dǎo)出功能,本文給大家介紹了SpringBoot中使用EasyExcel并行導(dǎo)出多個(gè)excel文件并壓縮zip后下載,需要的朋友可以參考下
    2024-09-09
  • Eclipse+Webservice簡(jiǎn)單開發(fā)實(shí)例

    Eclipse+Webservice簡(jiǎn)單開發(fā)實(shí)例

    這篇文章主要介紹了Eclipse+Webservice簡(jiǎn)單開發(fā)實(shí)例的相關(guān)資料,需要的朋友可以參考下
    2016-02-02
  • 簡(jiǎn)單了解Spring Web相關(guān)模塊運(yùn)行原理

    簡(jiǎn)單了解Spring Web相關(guān)模塊運(yùn)行原理

    這篇文章主要介紹了簡(jiǎn)單了解Spring Web相關(guān)模塊運(yùn)行原理,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-06-06
  • Spring Boot靜態(tài)資源路徑的配置與修改詳解

    Spring Boot靜態(tài)資源路徑的配置與修改詳解

    最近在做SpringBoot項(xiàng)目的時(shí)候遇到了“白頁”問題,通過查資料對(duì)SpringBoot訪問靜態(tài)資源做了總結(jié),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-09-09
  • Java動(dòng)態(tài)設(shè)置注解值及原理詳解

    Java動(dòng)態(tài)設(shè)置注解值及原理詳解

    這篇文章主要介紹了Java動(dòng)態(tài)設(shè)置注解值及原理詳解,AnnotationInvocationHandler是注解的代理hander,通過反射獲取類的注解時(shí)會(huì)通過AnnotationInvocationHandler創(chuàng)建代理對(duì)象并將數(shù)據(jù)存儲(chǔ)到memberValues里,需要的朋友可以參考下
    2023-11-11
  • SpringBoot+MyBatisPlus+MySQL8實(shí)現(xiàn)樹形結(jié)構(gòu)查詢

    SpringBoot+MyBatisPlus+MySQL8實(shí)現(xiàn)樹形結(jié)構(gòu)查詢

    這篇文章主要為大家詳細(xì)介紹了SpringBoot+MyBatisPlus+MySQL8實(shí)現(xiàn)樹形結(jié)構(gòu)查詢,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-06-06
  • Java實(shí)現(xiàn)手機(jī)號(hào)碼歸屬地查詢

    Java實(shí)現(xiàn)手機(jī)號(hào)碼歸屬地查詢

    這篇文章主要為大家詳細(xì)介紹了如何利用Java實(shí)現(xiàn)手機(jī)號(hào)碼歸屬地查詢功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-12-12
  • 用Java輕松讀取Word文檔內(nèi)容的常用方法

    用Java輕松讀取Word文檔內(nèi)容的常用方法

    這篇文章主要介紹了用Java輕松讀取Word文檔內(nèi)容的常用方法,對(duì)于doc格式使用Apache?POI庫中的HWPFDocument和WordExtractor類,對(duì)于docx格式使用XWPFDocument類,并通過遍歷段落和文本運(yùn)行對(duì)象來提取文本內(nèi)容,需要的朋友可以參考下
    2025-03-03
  • Java序列化與反序列化的實(shí)例分析講解

    Java序列化與反序列化的實(shí)例分析講解

    今天小編就為大家分享一篇關(guān)于Java序列化與反序列化的實(shí)例分析講解,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2018-12-12
  • Jmeter如何獲取jtl文件中所有的請(qǐng)求報(bào)文詳解

    Jmeter如何獲取jtl文件中所有的請(qǐng)求報(bào)文詳解

    JMeter的可以創(chuàng)建一個(gè)包含測(cè)試運(yùn)行結(jié)果的文本文件,這些通常稱為JTL文件,因?yàn)檫@是默認(rèn)擴(kuò)展名,但可以使用任何擴(kuò)展名,這篇文章主要給大家介紹了關(guān)于Jmeter如何獲取jtl文件中所有的請(qǐng)求報(bào)文的相關(guān)資料,需要的朋友可以參考下
    2021-09-09

最新評(píng)論