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

Java接口異步調(diào)用優(yōu)化技巧詳解

 更新時(shí)間:2023年05月06日 11:30:53   作者:浮生夢(mèng)  
本文詳細(xì)介紹了在Java開發(fā)中,如何通過(guò)異步調(diào)用等技巧來(lái)優(yōu)化接口的性能,有效避免阻塞和提高并發(fā)處理能力,提升系統(tǒng)的穩(wěn)定性和響應(yīng)速度

在日常項(xiàng)目中,我們經(jīng)常采用多線程異步調(diào)用的方式來(lái)提高接口的響應(yīng)時(shí)間。

在實(shí)際情況下,我們?nèi)绾瓮ㄟ^(guò)異步方式優(yōu)化我們的接口呢,有以下幾種常見(jiàn)思路

1,自己new線程或者線程池

如下我們把三個(gè)耗時(shí)操作交給新的線程或者線程池執(zhí)行。

當(dāng)請(qǐng)求過(guò)來(lái)的時(shí)候tomcat線程會(huì)等待子線程全部執(zhí)行完成,然后匯總結(jié)果進(jìn)行返回。

 /**
     * 這里會(huì)阻塞tomcat的線程
     */
    @GetMapping("getAllEgOne")
    public Map<String, Object> getAllEgOne() throws ExecutionException, InterruptedException {
        FutureTask<String> stringFutureTaskOne = new FutureTask<>(asyncService::getOne);
        FutureTask<String> stringFutureTaskTwo = new FutureTask<>(asyncService::getTwo);
        FutureTask<String> stringFutureTaskThree = new FutureTask<>(asyncService::getThree);
        new Thread(stringFutureTaskOne).start();
        new Thread(stringFutureTaskTwo).start();
        new Thread(stringFutureTaskThree).start();
        Map<String, Object> result = new HashMap<>();
        result.put("one", stringFutureTaskOne.get());
        result.put("two", stringFutureTaskTwo.get());
        result.put("three", stringFutureTaskThree.get());
        return result;
    }

2,Sping Mvc

我們返回一個(gè)Callable 這時(shí)候會(huì)開啟一個(gè)新的線程不會(huì)阻塞tomcat的線程

 /**
     * 這里不會(huì)阻塞tomcat的線程
     */
    @GetMapping("getAllEgTwo")
    public Callable<Map<String, Object>> getAllEgTwo() {
        return () -> {
            FutureTask<String> stringFutureTaskOne = new FutureTask<>(asyncService::getOne);
            FutureTask<String> stringFutureTaskTwo = new FutureTask<>(asyncService::getTwo);
            FutureTask<String> stringFutureTaskThree = new FutureTask<>(asyncService::getThree);
            new Thread(stringFutureTaskOne).start();
            new Thread(stringFutureTaskTwo).start();
            new Thread(stringFutureTaskThree).start();
            Map<String, Object> result = new HashMap<>(3);
            result.put("one", stringFutureTaskOne.get());
            result.put("two", stringFutureTaskTwo.get());
            result.put("three", stringFutureTaskThree.get());
            return result;
        };
    }

3,修改單個(gè)任務(wù)為批量任務(wù)

在項(xiàng)目中我們有很多數(shù)據(jù)庫(kù)的查詢,批量查詢要快于單個(gè)查詢,中間省了很多io操作。

思考能不能吧單個(gè)調(diào)用轉(zhuǎn)換成批量呢,針對(duì)并發(fā)比較高的接口。合并多個(gè)用戶的調(diào)用,轉(zhuǎn)換成一批進(jìn)行查詢。

把一個(gè)時(shí)間段內(nèi)的請(qǐng)求放進(jìn)隊(duì)列,然后通過(guò)定時(shí)任務(wù)進(jìn)行批量查詢,然后進(jìn)行響應(yīng)分發(fā)。

import com.example.demo.conf.SnowFlake;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;
/**
 * @author liwenchao
 */
@RestController
@RequestMapping("async")
@Slf4j
public class AsyncController {
    @Autowired
    private AsyncService asyncService;
    private final SnowFlake worker = new SnowFlake(1, 1, 1);
    private final LinkedBlockingQueue<RequestBody<Long, UserInfo>> queue = new LinkedBlockingQueue<>();
    @PostConstruct
    public void doWork() {
        ScheduledExecutorService service = Executors.newScheduledThreadPool(1);
        service.scheduleAtFixedRate(() -> {
            //每次運(yùn)行的時(shí)候 去拿MQ中的數(shù)據(jù)量
            int size = queue.size();
            if (size == 0) {
                return;
            }
            log.info("批量獲取任務(wù):{}-{}", Thread.currentThread().getName(), size);
            //多次請(qǐng)求收集到一起一塊去批量請(qǐng)求下面的需要的數(shù)據(jù)
            List<Long> requestBodyList = new ArrayList<>();
            List<RequestBody<Long, UserInfo>> requestBodies = new ArrayList<>();
            for (int i = 0; i < size; i++) {
                RequestBody<Long, UserInfo> requestBody = queue.poll();
                requestBodies.add(requestBody);
                Long requestParam = requestBody.getRequestParam();
                requestBodyList.add(requestParam);
            }
            List<UserInfo> fourBatch;
            try {
                fourBatch = asyncService.getFourBatch(requestBodyList);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            if (CollectionUtils.isEmpty(fourBatch)) {
                return;
            }
            for (UserInfo x : fourBatch) {
                for (RequestBody<Long, UserInfo> y : requestBodies) {
                    if (x.getId().equals(y.getRequestParam())) {
                        y.getResult().complete(x);
                        break;
                    }
                }
            }
        }, 1000L, 50L, TimeUnit.MILLISECONDS);
    }
    /**
     * ● 插入
     * 1.add(e):當(dāng)阻塞隊(duì)列滿時(shí),再往隊(duì)列里add插入元素會(huì)拋IllegalStateException:Queue full
     * 2.offer(e):插入方法,成功true失敗返回false
     * 3.put(e):當(dāng)阻塞隊(duì)列滿時(shí),生產(chǎn)者線程繼續(xù)往隊(duì)列里添加元素,隊(duì)列會(huì)一直阻塞生產(chǎn)者線程。直到put數(shù)據(jù)or響應(yīng)中斷退出
     * 4.offer(e,time,unit):當(dāng)阻塞隊(duì)列滿的時(shí)候,隊(duì)列會(huì)阻塞生產(chǎn)者線程一定時(shí)間,超過(guò)限時(shí)后生產(chǎn)者線程會(huì)退出。
     * <p>
     * ● 移除
     * 1.remove():當(dāng)隊(duì)列為空的時(shí)候,再往隊(duì)列里remove移除元素會(huì)拋NoSuchElementException
     * 2.poll():移除方法,成功返回出隊(duì)列的元素,隊(duì)列里沒(méi)有就返回null。
     * 3.take():當(dāng)隊(duì)列為空消費(fèi)者線程試圖從隊(duì)列里take元素,隊(duì)列會(huì)一直阻塞消費(fèi)者線程知道隊(duì)列可用
     * 4.poll(time,unit):當(dāng)隊(duì)列為空的時(shí)候,會(huì)阻塞一段時(shí)間超時(shí)后消費(fèi)者線程退出。
     * <p>
     * ● 檢查
     * 1.element():當(dāng)隊(duì)列為空時(shí)直接拋出異常
     * 2.peek():當(dāng)隊(duì)列為空時(shí)阻塞
     * <p>
     * 這里不會(huì)阻塞tomcat的線程
     */
    @GetMapping("getAllEgFour")
    public UserInfo getAllEgFour(Long userId) throws ExecutionException, InterruptedException {
        if (userId == null) {
            userId = worker.nextId();
        }
        log.info("開始獲取數(shù)據(jù): {}: {}", Thread.currentThread().getName(), userId);
        RequestBody<Long, UserInfo> objectObjectRequestBody = new RequestBody<>();
        CompletableFuture<UserInfo> completableFuture = new CompletableFuture<>();
        objectObjectRequestBody.setRequestParam(userId);
        objectObjectRequestBody.setResult(completableFuture);
        queue.add(objectObjectRequestBody);
        UserInfo userInfo = completableFuture.get();
        log.info("完成獲取數(shù)據(jù): {}: {}", Thread.currentThread().getName(), userInfo);
        return userInfo;
    }
}

到此這篇關(guān)于Java接口異步調(diào)用優(yōu)化技巧詳解的文章就介紹到這了,更多相關(guān)Java接口異步調(diào)用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Sentinel的熔斷降級(jí)、資源規(guī)則詳解與實(shí)例

    Sentinel的熔斷降級(jí)、資源規(guī)則詳解與實(shí)例

    這篇文章主要介紹了Sentinel的熔斷降級(jí)、資源規(guī)則詳解與實(shí)例,Sentinel是阿里巴巴開源的一款流量控制和熔斷降級(jí)的框架,它主要用于保護(hù)分布式系統(tǒng)中的服務(wù)穩(wěn)定性,Sentinel通過(guò)對(duì)服務(wù)進(jìn)行流量控制和熔斷降級(jí),可以有效地保護(hù)系統(tǒng)的穩(wěn)定性,需要的朋友可以參考下
    2023-09-09
  • multi-catch和try-catch異常處理知識(shí)點(diǎn)詳解

    multi-catch和try-catch異常處理知識(shí)點(diǎn)詳解

    在本篇文章里我們給大家分享了一篇關(guān)于multi-catch和try-catch異常處理知識(shí)點(diǎn)內(nèi)容,有需要的朋友們可以參考學(xué)習(xí)下。
    2019-11-11
  • Spring?Lifecycle?和?SmartLifecycle區(qū)別面試精講

    Spring?Lifecycle?和?SmartLifecycle區(qū)別面試精講

    這篇文章主要為大家介紹了Spring?Lifecycle和SmartLifecycle的區(qū)別面試精講,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-10-10
  • Java簡(jiǎn)單使用redis-zset實(shí)現(xiàn)排行榜

    Java簡(jiǎn)單使用redis-zset實(shí)現(xiàn)排行榜

    這篇文章主要介紹了Java簡(jiǎn)單使用redis-zset實(shí)現(xiàn)排行榜,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • 淺談java泛型的作用及其基本概念

    淺談java泛型的作用及其基本概念

    下面小編就為大家?guī)?lái)一篇淺談java泛型的作用及其基本概念。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-08-08
  • SpringBoot利用隨機(jī)鹽值實(shí)現(xiàn)密碼的加密與驗(yàn)證

    SpringBoot利用隨機(jī)鹽值實(shí)現(xiàn)密碼的加密與驗(yàn)證

    這篇文章主要為大家詳細(xì)介紹了SpringBoot如何利用隨機(jī)鹽值實(shí)現(xiàn)密碼的加密與驗(yàn)證,文中的示例代碼講解詳細(xì),有需要的小伙伴可以參考下
    2024-02-02
  • 利用Spring IOC技術(shù)實(shí)現(xiàn)用戶登錄驗(yàn)證機(jī)制

    利用Spring IOC技術(shù)實(shí)現(xiàn)用戶登錄驗(yàn)證機(jī)制

    這篇文章主要為大家詳細(xì)介紹了Spring IOC技術(shù)實(shí)現(xiàn)用戶登錄驗(yàn)證機(jī)制的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-10-10
  • Spring中BeanFactory解析bean詳解

    Spring中BeanFactory解析bean詳解

    本篇文章主要介紹了Spring中BeanFactory解析bean詳解 ,詳細(xì)的介紹了使用BeanFactory對(duì)bean進(jìn)行解析的實(shí)例,有興趣的可以了解一下。
    2017-04-04
  • Java基礎(chǔ)之淺談hashCode()和equals()

    Java基礎(chǔ)之淺談hashCode()和equals()

    今天給大家?guī)?lái)的是關(guān)于Java基礎(chǔ)的相關(guān)知識(shí),文章圍繞著hashCode()和equals()展開,文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下
    2021-06-06
  • 深入探究SpringBoot中的Elasticsearch自動(dòng)配置原理及用法

    深入探究SpringBoot中的Elasticsearch自動(dòng)配置原理及用法

    SpringBoot中的Elasticsearch自動(dòng)配置為我們提供了一種快速集成Elasticsearch的方式,使我們可以在SpringBoot應(yīng)用程序中輕松地使用Elasticsearch,本文將介紹Spring Boot中的Elasticsearch自動(dòng)配置的作用、原理和使用方法
    2023-07-07

最新評(píng)論