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

Java多線程并發(fā)之線程池任務(wù)請(qǐng)求攔截測(cè)試實(shí)例

 更新時(shí)間:2023年12月14日 09:10:56   作者:Terisadeng  
這篇文章主要介紹了Java多線程并發(fā)之線程池任務(wù)請(qǐng)求攔截測(cè)試實(shí)例,隊(duì)列中永遠(yuǎn)沒(méi)有線程被加入,即使線程池已滿,也不會(huì)導(dǎo)致被加入排隊(duì)隊(duì)列,實(shí)現(xiàn)了只有線程池存在空閑線程的時(shí)候才會(huì)接受新任務(wù)的需求,需要的朋友可以參考下

一、需求

前端會(huì)傳入一個(gè)存儲(chǔ)編碼的list,后臺(tái)接收到編碼通過(guò)計(jì)算返回每個(gè)編碼對(duì)應(yīng)的值,每個(gè)編碼計(jì)算出來(lái)的值是固定不變的。

二、設(shè)計(jì)方案

因?yàn)榍岸苏?qǐng)求響應(yīng)有一個(gè)時(shí)常要求,比如100ms。

而這個(gè)計(jì)算比較耗時(shí),因此為了請(qǐng)求能夠快速響應(yīng),在第一個(gè)請(qǐng)求過(guò)來(lái)時(shí)判斷redis緩存是否存儲(chǔ)編碼對(duì)應(yīng)的計(jì)算值,如果沒(méi)有就直接返回空,前端根據(jù)這個(gè)空值使用補(bǔ)償方案的默認(rèn)值。

后臺(tái)通過(guò)線程池執(zhí)行計(jì)算方法,然后存入redis,這樣下次用戶帶著相同的編碼請(qǐng)求就可以直接從緩存獲取,不用重復(fù)計(jì)算。

這里的問(wèn)題在于,當(dāng)并發(fā)量高的情況下,比如50個(gè)用戶帶著相同的編碼調(diào)用計(jì)算方法,而實(shí)際上計(jì)算方法只需要調(diào)用一次就可以了。

因此我們需要在將任務(wù)提交到線程池之前判斷線程池中執(zhí)行線程的數(shù)量來(lái)決定是否要將任務(wù)提交到線程池。

另外這里千萬(wàn)不能使用直接創(chuàng)建線程的方式,這會(huì)導(dǎo)致并發(fā)情況下突然創(chuàng)建大量線程,導(dǎo)致系統(tǒng)cpu飆升卡死。

三、測(cè)試

1、線程池實(shí)現(xiàn)類,提供全局唯一的線程池實(shí)例

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
 * 固定大小的線程池
 */
public class DisCardThreadPool
{
    private static DisCardThreadPool disCardThreadPool=new DisCardThreadPool();
    /*
     * 將構(gòu)造方法訪問(wèn)修飾符設(shè)為私有,禁止任意實(shí)例化。
     */
    private DisCardThreadPool() {
    }
    /**
     * 核心線程數(shù)
     */
    int corePoolSize = 1;
    /**
     * 最大線程數(shù)
     */
    int maximumPoolSize = 1;
    /**
     * 空閑線程存活時(shí)間
     */
    long keepAliveTime = 10;
    /*
     * 線程池單例創(chuàng)建方法
     */
    public static DisCardThreadPool newInstance() {
        return disCardThreadPool;
    }
    private final ThreadPoolExecutor mThreadPool=new ThreadPoolExecutor(corePoolSize,maximumPoolSize,keepAliveTime, TimeUnit.MILLISECONDS,new ArrayBlockingQueue<>(10), new ThreadPoolExecutor.DiscardPolicy());
    public void execute(Runnable r){
        mThreadPool.execute(r);
    }
    /**
     * 隊(duì)列中等待執(zhí)行的任務(wù)數(shù)目
     * @return
     */
    public synchronized int getQueue(){
        return mThreadPool.getQueue().size();
    }
    /*
     * 獲取線程池中剩余線程數(shù)目
     * 獲取的結(jié)果不準(zhǔn)確
     */
    public synchronized int getActiveCount(){
        return mThreadPool.getActiveCount();
    }

2、測(cè)試類

這里通過(guò)CountDownLatch類同時(shí)啟動(dòng)多個(gè)線程來(lái)模擬并發(fā)請(qǐng)求

import com.teriste.service.threadpool.DisCardThreadPool;
import org.junit.Test;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
/**
 * 模擬并發(fā)向線程池提交任務(wù)。
 * 需求:使得線程池滿之后其他請(qǐng)求都不執(zhí)行
 */
public class MultiThreadConcurrencyTest {
    //獲取線程池實(shí)例
    private static DisCardThreadPool threadPool=DisCardThreadPool.newInstance();
    @Test
    public void test(){
        //創(chuàng)建大小20的計(jì)數(shù)器,使得20個(gè)線程同時(shí)執(zhí)行,模擬并發(fā)
       CountDownLatch countDownLatch=new CountDownLatch(20);
       for (int i=0;i<20;i++){
           InvokeThread thread=new InvokeThread(countDownLatch);
           System.out.println("創(chuàng)建線程:"+thread.getName());
           thread.start();
           //啟動(dòng)一個(gè)線程,計(jì)數(shù)器就減一,同時(shí)在線程的run方法中阻塞線程,等待計(jì)數(shù)器喚醒
           countDownLatch.countDown();
       }
        try {
           //阻塞主線程,防止子線程還沒(méi)執(zhí)行主線程結(jié)束導(dǎo)致子線程無(wú)法執(zhí)行
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    //線程池執(zhí)行線程
    public static void invokeThread(){
        //當(dāng)排隊(duì)隊(duì)列有線程等待時(shí)不繼續(xù)添加線程
        synchronized (MultiThreadConcurrencyTest.class){
            //System.out.println("等待隊(duì)列大小:"+threadPool.getQueue());
            //官方api指出getActiveCount()無(wú)法獲取準(zhǔn)確的存獲線程數(shù)
            //因?yàn)檫@里是根據(jù)隊(duì)列中待執(zhí)行任務(wù)數(shù)來(lái)判斷,因此如果線程池大小為1,實(shí)際上會(huì)有兩個(gè)線程被執(zhí)行,
            //一個(gè)線程是進(jìn)入線程池,還有一個(gè)線程判斷此時(shí)隊(duì)列待執(zhí)行線程數(shù)是0會(huì)進(jìn)入待執(zhí)行隊(duì)列,因此最終執(zhí)行線程數(shù)是線程池大小+1
            System.out.println("排隊(duì)隊(duì)列中的線程個(gè)數(shù):"+threadPool.getQueue());
            if (threadPool.getQueue()<=0){
                threadPool.execute(new WorkThread());
            }
        }
    }
}
//調(diào)用線程池執(zhí)行任務(wù)的類,模擬外部請(qǐng)求實(shí)體發(fā)起請(qǐng)求
class InvokeThread extends Thread{
    private CountDownLatch countDownLatch;
    public InvokeThread(CountDownLatch countDownLatch){
        this.countDownLatch=countDownLatch;
    }
    @Override
    public void run(){
        try {
            //等待計(jì)數(shù)器喚醒
            countDownLatch.await();
            //向線程池提交線程
            MultiThreadConcurrencyTest.invokeThread();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
//任務(wù)類
class WorkThread implements Runnable{
    @Override
    public void run() {
        String path="E:\\測(cè)試";
        File file=new File(path);
        if(!file.exists()){
            file.mkdirs();//創(chuàng)建目錄
        }
        String fileName=Thread.currentThread().getName()+System.currentTimeMillis();
        File newFile=new File(path,fileName);
        try {
            newFile.createNewFile();
        } catch (IOException e) {
            e.printStackTrace();
        }
        //在線程池中有可能是不同的線程使用相同的名稱
        //因?yàn)榫€程池中上個(gè)結(jié)束的線程繼續(xù)使用來(lái)執(zhí)行下個(gè)線程
        System.out.println("當(dāng)前執(zhí)行的線程的名稱:"+Thread.currentThread().getName()+fileName);
    }
}

3、如果放開(kāi)對(duì)排隊(duì)隊(duì)列的判斷可以看到,當(dāng)線程池滿了之后執(zhí)行的是ArrayBlockingQueue.offer(E e);方法:

這說(shuō)明我們可以通過(guò)繼承ArrayBlockingQueue類實(shí)現(xiàn)自己的排隊(duì)隊(duì)列,當(dāng)線程池滿了之后調(diào)用offer方法時(shí),我們直接丟棄任務(wù)什么都不做,這樣就可以準(zhǔn)確實(shí)現(xiàn)上面的方案,并且可以去掉對(duì)隊(duì)列中待執(zhí)行線程的判斷,從而不需要加鎖,提高執(zhí)行效率。

下面是自定義隊(duì)列的實(shí)現(xiàn):

import java.util.Collection;
import java.util.concurrent.ArrayBlockingQueue;
/**
 * 線程池使用該類時(shí)執(zhí)行插入方法時(shí)不會(huì)向隊(duì)列中插入數(shù)據(jù),會(huì)直接丟棄或記錄日志
 */
public class EmptyArrayBlockingQueue<E> extends ArrayBlockingQueue{
    public EmptyArrayBlockingQueue(int capacity) {
        super(capacity);
    }
    public EmptyArrayBlockingQueue(int capacity, boolean fair) {
        super(capacity, fair);
    }
    public EmptyArrayBlockingQueue(int capacity, boolean fair, Collection c) {
        super(capacity, fair, c);
    }
    /**
     * 注意這里重寫的父類方法參數(shù)是泛型參數(shù)
     * 由于Java的類型擦除,在編譯時(shí)會(huì)自動(dòng)變?yōu)镺bject類型
     * 因此這里使用Object類型實(shí)際上就是重寫的父類方法
     * @param e
     * @return
     */
    @Override
    public boolean offer(Object e) {
        /**不執(zhí)行將線程加入隊(duì)列的操作,這樣隊(duì)列永遠(yuǎn)為空
        超過(guò)線程池核心線程數(shù)的線程實(shí)際上在這里都被丟棄了
        可以增加記錄日志的操作
         */
        return true;
    }
}

下面是修改后的線程池類:

import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
 * 固定大小的線程池
 */
public class DisCardThreadPool
{
    private static DisCardThreadPool disCardThreadPool=new DisCardThreadPool();
    /*
     * 將構(gòu)造方法訪問(wèn)修飾符設(shè)為私有,禁止任意實(shí)例化。
     */
    private DisCardThreadPool() {
    }
    /**
     * 核心線程數(shù)
     */
    int corePoolSize = 1;
    /**
     * 最大線程數(shù)
     */
    int maximumPoolSize = 1;
    /**
     * 空閑線程存活時(shí)間
     */
    long keepAliveTime = 10;
    /*
     * 線程池單例創(chuàng)建方法
     */
    public static DisCardThreadPool newInstance() {
        return disCardThreadPool;
    }
    private final ThreadPoolExecutor mThreadPool=new ThreadPoolExecutor(corePoolSize,maximumPoolSize,keepAliveTime, TimeUnit.MILLISECONDS,new EmptyArrayBlockingQueue<>(10),
            new ThreadPoolExecutor.DiscardPolicy());
    public void execute(Runnable r){
        mThreadPool.execute(r);
    }
    /**
     * 隊(duì)列中等待執(zhí)行的任務(wù)數(shù)目
     * @return
     */
    public synchronized int getQueue(){
        return mThreadPool.getQueue().size();
    }
    /*
     * 獲取線程池中剩余線程數(shù)目
     * 獲取的結(jié)果不準(zhǔn)確
     */
    public synchronized int getActiveCount(){
        return mThreadPool.getActiveCount();
    }
}

下面是測(cè)試類:

import com.teriste.service.threadpool.DisCardThreadPool;
import org.junit.Test;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
/**
 * 模擬并發(fā)向線程池提交任務(wù)。
 * 需求:使得線程池滿之后其他請(qǐng)求都不執(zhí)行
 */
public class MultiThreadConcurrencyTest {
    //獲取線程池實(shí)例
    private static DisCardThreadPool threadPool=DisCardThreadPool.newInstance();
    @Test
    public void test(){
        //創(chuàng)建大小20的計(jì)數(shù)器,使得20個(gè)線程同時(shí)執(zhí)行,模擬并發(fā)
       CountDownLatch countDownLatch=new CountDownLatch(20);
       for (int i=0;i<20;i++){
           InvokeThread thread=new InvokeThread(countDownLatch);
           System.out.println("創(chuàng)建線程:"+thread.getName());
           thread.start();
           //啟動(dòng)一個(gè)線程,計(jì)數(shù)器就減一,同時(shí)在線程的run方法中阻塞線程,等待計(jì)數(shù)器喚醒
           countDownLatch.countDown();
       }
        try {
           //阻塞主線程,防止子線程還沒(méi)執(zhí)行主線程結(jié)束導(dǎo)致子線程無(wú)法執(zhí)行
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    //線程池執(zhí)行線程
    public static void invokeThread(){
        //當(dāng)排隊(duì)隊(duì)列有線程等待時(shí)不繼續(xù)添加線程
        synchronized (MultiThreadConcurrencyTest.class){
            //System.out.println("等待隊(duì)列大小:"+threadPool.getQueue());
            //官方api指出getActiveCount()無(wú)法獲取準(zhǔn)確的存獲線程數(shù)
            //因?yàn)檫@里是根據(jù)隊(duì)列中待執(zhí)行任務(wù)數(shù)來(lái)判斷,因此如果線程池大小為1,實(shí)際上會(huì)有兩個(gè)線程被執(zhí)行,
            //一個(gè)線程是進(jìn)入線程池,還有一個(gè)線程判斷此時(shí)隊(duì)列待執(zhí)行線程數(shù)是0會(huì)進(jìn)入待執(zhí)行隊(duì)列,因此最終執(zhí)行線程數(shù)是線程池大小+1
            System.out.println("排隊(duì)隊(duì)列中的線程個(gè)數(shù):"+threadPool.getQueue());
            //if (threadPool.getQueue()<=0){
                threadPool.execute(new WorkThread());
            //}
        }
    }
}
//調(diào)用線程池執(zhí)行任務(wù)的類,模擬外部請(qǐng)求實(shí)體發(fā)起請(qǐng)求
class InvokeThread extends Thread{
    private CountDownLatch countDownLatch;
    public InvokeThread(CountDownLatch countDownLatch){
        this.countDownLatch=countDownLatch;
    }
    @Override
    public void run(){
        try {
            //等待計(jì)數(shù)器喚醒
            countDownLatch.await();
            //向線程池提交線程
            MultiThreadConcurrencyTest.invokeThread();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
//任務(wù)類
class WorkThread implements Runnable{
    @Override
    public void run() {
        String path="E:\\測(cè)試";
        File file=new File(path);
        if(!file.exists()){
            file.mkdirs();//創(chuàng)建目錄
        }
        String fileName=Thread.currentThread().getName()+System.currentTimeMillis();
        File newFile=new File(path,fileName);
        try {
            newFile.createNewFile();
        } catch (IOException e) {
            e.printStackTrace();
        }
        //在線程池中有可能是不同的線程使用相同的名稱
        //因?yàn)榫€程池中上個(gè)結(jié)束的線程繼續(xù)使用來(lái)執(zhí)行下個(gè)線程
        System.out.println("當(dāng)前執(zhí)行的線程的名稱:"+Thread.currentThread().getName()+fileName);
    }
}

測(cè)試結(jié)果:

從測(cè)試結(jié)果可以看到,隊(duì)列中永遠(yuǎn)沒(méi)有線程被加入,即使線程池已滿,也不會(huì)導(dǎo)致被加入排隊(duì)隊(duì)列,實(shí)現(xiàn)了只有線程池存在空閑線程的時(shí)候才會(huì)接受新任務(wù)的需求。

到此這篇關(guān)于Java多線程并發(fā)之線程池任務(wù)請(qǐng)求攔截測(cè)試實(shí)例的文章就介紹到這了,更多相關(guān)Java線程池任務(wù)請(qǐng)求攔截測(cè)試內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringSession會(huì)話管理之Redis與JDBC存儲(chǔ)實(shí)現(xiàn)方式

    SpringSession會(huì)話管理之Redis與JDBC存儲(chǔ)實(shí)現(xiàn)方式

    本文將詳細(xì)介紹Spring Session的核心概念、特性以及如何使用Redis和JDBC來(lái)實(shí)現(xiàn)會(huì)話存儲(chǔ),幫助開(kāi)發(fā)者構(gòu)建更加健壯和可擴(kuò)展的應(yīng)用系統(tǒng),希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-04-04
  • mybatis-plus?如何使用雪花算法ID生成策略

    mybatis-plus?如何使用雪花算法ID生成策略

    這篇文章主要介紹了mybatis-plus如何使用雪花算法ID生成策略,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • springboot整合shiro的過(guò)程詳解

    springboot整合shiro的過(guò)程詳解

    Shiro 是一個(gè)強(qiáng)大的簡(jiǎn)單易用的 Java 安全框架,主要用來(lái)更便捷的 認(rèn)證,授權(quán),加密,會(huì)話管理,這篇文章給大家詳細(xì)介紹Shiro 工作原理及架構(gòu)圖,通過(guò)實(shí)例圖文相結(jié)合給大家介紹的非常詳細(xì),需要的朋友參考下吧
    2021-10-10
  • java單例模式4種使用方式分享

    java單例模式4種使用方式分享

    到底如何寫一個(gè)在生產(chǎn)環(huán)境中使用的單實(shí)例模式?下面是4種方式,大家參考使用吧
    2014-02-02
  • Java TimeoutException:服務(wù)調(diào)用超時(shí)異常的正確解決方案

    Java TimeoutException:服務(wù)調(diào)用超時(shí)異常的正確解決方案

    在現(xiàn)代軟件開(kāi)發(fā)中,服務(wù)間通信是構(gòu)建分布式系統(tǒng)的基礎(chǔ),然而,網(wǎng)絡(luò)延遲、服務(wù)負(fù)載、資源競(jìng)爭(zhēng)等因素都可能導(dǎo)致服務(wù)調(diào)用超時(shí),TimeoutException是Java中表示服務(wù)調(diào)用超時(shí)的常見(jiàn)異常之一,本文將探討TimeoutException的成因及解決方案,需要的朋友可以參考下
    2024-12-12
  • SpringBoot整合POI導(dǎo)出通用Excel的方法示例

    SpringBoot整合POI導(dǎo)出通用Excel的方法示例

    這篇文章主要介紹了SpringBoot整合POI導(dǎo)出通用Excel的方法示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • 淺析java 的 static 關(guān)鍵字用法

    淺析java 的 static 關(guān)鍵字用法

    這篇文章主要介紹了淺析java 的 static 關(guān)鍵字用法的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2016-06-06
  • 總結(jié)Java對(duì)象被序列化的兩種方法

    總結(jié)Java對(duì)象被序列化的兩種方法

    今天給大家?guī)?lái)的是關(guān)于Java的相關(guān)知識(shí),文章圍繞著Java對(duì)象被序列化的兩種方法展開(kāi),文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下
    2021-06-06
  • 指定jdk啟動(dòng)jar包的方法總結(jié)

    指定jdk啟動(dòng)jar包的方法總結(jié)

    這篇文章主要給大家總結(jié)介紹了關(guān)于指定jdk啟動(dòng)jar包的方法,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2023-07-07
  • 聊聊@Autowired注解注入,寫接口名字還是實(shí)現(xiàn)類的名字

    聊聊@Autowired注解注入,寫接口名字還是實(shí)現(xiàn)類的名字

    這篇文章主要介紹了聊聊@Autowired注解注入,寫接口名字還是實(shí)現(xiàn)類的名字,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11

最新評(píng)論

保康县| 嘉禾县| 定兴县| 常州市| 德江县| 邯郸县| 阿克| 金寨县| 铜川市| 陇川县| 鹰潭市| 榆林市| 龙口市| 龙陵县| 迁安市| 逊克县| 吉林省| 平顶山市| 灵武市| 苏尼特左旗| 敖汉旗| 阳泉市| 多伦县| 柯坪县| 宁武县| 三原县| 尼木县| 广州市| 黑山县| 金沙县| 湖南省| 宁德市| 扎囊县| 咸宁市| 太湖县| 宾川县| 宜兰县| 高阳县| 毕节市| 武强县| 纳雍县|