Future和AsyncResult的異步和同步

Future和AsyncResult是什么吏饿?后面再看!

先直接上代碼:

Demo 1

  1. 第一步脆霎,用最簡單的方法生成一個可運行的Spring Boot項目:https://start.spring.io/ (Dependencies(依賴)加個Spring Web
  2. 生成的項目中,找到啟動類DemoApplication,添加異步注解@EnableAsync
package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@EnableAsync
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}
  1. 新建 FutureService.java丁眼,里面有三個方法,返回值用 AsyncResult 包裝一下昭殉,為了方便看效果苞七,加上一些日志
package com.example.demo.service;

import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;

import java.util.concurrent.Future;

@Service
@Slf4j
public class FutureService {
    @Async
    public Future<String> jobOne() throws InterruptedException {
        System.out.println("job 1 start...");
        long start = System.currentTimeMillis();
        Thread.sleep(2000);
        long end = System.currentTimeMillis();
        System.out.println("job 1 completed, it took " + (end - start));
        return new AsyncResult<>( "job 1 success");
    }
    @Async
    public Future<String> jobTwo() throws InterruptedException {
        System.out.println("job 2 start...");
        long start = System.currentTimeMillis();
        Thread.sleep(500);
        long end = System.currentTimeMillis();
        System.out.println("job 2 completed, it took " + (end - start));
        return new AsyncResult<>( "job 2 success");
    }
    @Async
    public Future<String> jobThree() throws InterruptedException {
        System.out.println("job 3 start...");
        long start = System.currentTimeMillis();
        Thread.sleep(1000);
        long end = System.currentTimeMillis();
        System.out.println("job 3 completed, it took "+ (end - start));
        return new AsyncResult<>( "job 3 success");
    }
}
  1. 新建 DemoControllerl.java,調(diào)用 FutureService 里的三個方法
package com.example.demo.controller;

import com.example.demo.service.FutureService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

@RestController
public class DemoController {
    @Autowired
    private FutureService futureService;

    @RequestMapping("/test")
    public String test() throws InterruptedException, ExecutionException {
        long start = System.currentTimeMillis();
        Future<String> f1 = futureService.jobOne();
        Future<String> f2 = futureService.jobTwo();
        Future<String> f3 = futureService.jobThree();
        // 三個方法都執(zhí)行完畢才繼續(xù)執(zhí)行后面代碼
        while (!f1.isDone() || !f2.isDone() || !f3.isDone()){
            System.out.println("Waiting....");
            Thread.sleep(300);
        }
        // 三個方法都執(zhí)行完畢
        long end = System.currentTimeMillis();
        System.out.println("Result 1: " + f1.get());
        System.out.println("Result 2: " + f2.get());
        System.out.println("Result 3: " + f3.get());
        System.out.println("Execution Time : " + (end - start));
        return "success";
    }
}

  1. 運行啟動類 DemoApplication挪丢,啟動成功后訪問 http://localhost:8080/test蹂风, 可以看到以下效果:
job 1 start...
job 2 start...
Waiting....
job 3 start...
Waiting....
job 2 completed, it took 501
Waiting....
Waiting....
job 3 completed, it took 1000
Waiting....
Waiting....
Waiting....
job 1 completed, it took 2002
Result 1: job 1 success
Result 2: job 2 success
Result 3: job 3 success
Execution Time : 2114

從打印的日志可以看出來,并不是按照三個方法調(diào)用的順序乾蓬,一個方法執(zhí)行完再執(zhí)行下一個方法惠啄,三個方法的運行時間:501任内、1000撵渡、2002,而總的運行時間為2114死嗦,這個例子中趋距,三個方法是異步執(zhí)行的。越除。

Demo 2

還是用上面的代碼棚品,但是 DemoController 是代碼順序稍微調(diào)整一下:按照平時的習慣,執(zhí)行一個方法廊敌,輸出結(jié)果铜跑。

@RestController
public class DemoController {
    @Autowired
    private FutureService futureService;

    @RequestMapping("/test")
    public String test() throws InterruptedException, ExecutionException {
        long start = System.currentTimeMillis();
        Future<String> f1 = futureService.jobOne();
        System.out.println("Result 1: " + f1.get());
        Future<String> f2 = futureService.jobTwo();
        System.out.println("Result 2: " + f2.get());
        Future<String> f3 = futureService.jobThree();
        System.out.println("Result 3: " + f3.get());
        long end = System.currentTimeMillis();
        System.out.println("Execution Time : " + (end - start));
        return "success";
    }
}

重新運行啟動類 DemoApplication,可以看到以下結(jié)果:

job 1 start...
job 1 completed, it took 2005
Result 1: job 1 success
job 2 start...
job 2 completed, it took 502
Result 2: job 2 success
job 3 start...
job 3 completed, it took 1004
Result 3: job 3 success
Execution Time : 3516

這次的輸出結(jié)果骡澈,和沒有用Future和AsyncResult的方法是一樣的效果锅纺,每個方法按順序執(zhí)行,一個結(jié)果后再執(zhí)行下一個肋殴。

概念

Future

Future是 java.util.concurrent 包里的一個接口
https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Future.html

  • cancel(boolean mayInterruptIfRunning): boolean
  • get()
  • get(long timeout, TimeUnit unit)
  • isCancelled(): boolean
  • isDone(): boolean

2022.9.14 更新
最近由于項目上對一些慢接口的優(yōu)化囤锉,把很多接口加上了@Async坦弟,上線運行一段時間后,發(fā)現(xiàn)線程數(shù)量激增9俚亍D鸢!

@Async默認使用Spring的SimpleAsyncTaskExecutor:

TaskExecutor implementation that fires up a new Thread for each task, executing it asynchronously.

每提交一個任務驱入,就會創(chuàng)建一個線程赤炒,能不炸嗎?
解決方法: @Async(value="customExecutor")亏较, value參數(shù)傳入自定義的線程池莺褒。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市雪情,隨后出現(xiàn)的幾起案子遵岩,更是在濱河造成了極大的恐慌,老刑警劉巖巡通,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件尘执,死亡現(xiàn)場離奇詭異,居然都是意外死亡宴凉,警方通過查閱死者的電腦和手機誊锭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來跪解,“玉大人炉旷,你說我怎么就攤上這事〔婕ィ” “怎么了窘行?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長图仓。 經(jīng)常有香客問我罐盔,道長,這世上最難降的妖魔是什么救崔? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任惶看,我火速辦了婚禮,結(jié)果婚禮上六孵,老公的妹妹穿的比我還像新娘纬黎。我一直安慰自己,他們只是感情好劫窒,可當我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布本今。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪冠息。 梳的紋絲不亂的頭發(fā)上挪凑,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天,我揣著相機與錄音逛艰,去河邊找鬼躏碳。 笑死,一個胖子當著我的面吹牛散怖,可吹牛的內(nèi)容都是我干的菇绵。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼杭抠,長吁一口氣:“原來是場噩夢啊……” “哼脸甘!你這毒婦竟也來了恳啥?” 一聲冷哼從身側(cè)響起偏灿,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎钝的,沒想到半個月后翁垂,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡硝桩,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年沿猜,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片碗脊。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡啼肩,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出衙伶,到底是詐尸還是另有隱情祈坠,我是刑警寧澤,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布矢劲,位于F島的核電站赦拘,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏芬沉。R本人自食惡果不足惜躺同,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望丸逸。 院中可真熱鬧蹋艺,春花似錦、人聲如沸黄刚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至侍芝,卻和暖如春研铆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背州叠。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工棵红, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人咧栗。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓逆甜,卻偏偏與公主長得像,于是被迫代替她去往敵國和親致板。 傳聞我的和親對象是個殘疾皇子交煞,可洞房花燭夜當晚...
    茶點故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內(nèi)容