亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

java實(shí)現(xiàn)手寫一個(gè)簡單版的線程池

 更新時(shí)間:2021年08月02日 15:43:33   作者:迷路國王  
有些人可能對線程池比較陌生,并且更不熟悉線程池的工作原理。本文就來手寫一個(gè)簡單版的線程池,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

有些人可能對線程池比較陌生,并且更不熟悉線程池的工作原理。所以他們在使用線程的時(shí)候,多數(shù)情況下都是new Thread來實(shí)現(xiàn)多線程。但是,往往良好的多線程設(shè)計(jì)大多都是使用線程池來實(shí)現(xiàn)的。 為什么要使用線程 降低資源的消耗。降低線程創(chuàng)建和銷毀的資源消耗。提高響應(yīng)速度:線程的創(chuàng)建時(shí)間為T1,執(zhí)行時(shí)間T2,銷毀時(shí)間T3,免去T1和T3的時(shí)間提高線程的可管理性

下圖所示為線程池的實(shí)現(xiàn)原理:調(diào)用方不斷向線程池中提交任務(wù);線程池中有一組線程,不斷地從隊(duì)列中取任務(wù),這是一個(gè)典型的生產(chǎn)者-消費(fèi)者模型。

要實(shí)現(xiàn)一個(gè)線程池,有幾個(gè)問題需要考慮:

  • 隊(duì)列設(shè)置多長?如果是無界的,調(diào)用方不斷往隊(duì)列中方任務(wù),可能導(dǎo)致內(nèi)存耗盡。如果是有界的,當(dāng)隊(duì)列滿了之后,調(diào)用方如何處理?
  • 線程池中的線程個(gè)數(shù)是固定的,還是動態(tài)變化的?
  • 每次提交新任務(wù),是放入隊(duì)列?還是開新線程
  • 當(dāng)沒有任務(wù)的時(shí)候,線程是睡眠一小段時(shí)間?還是進(jìn)入阻塞?如果進(jìn)入阻塞,如何喚醒?

針對問題4,有3種做法:

  • 不使用阻塞隊(duì)列,只使用一般的線程安全的隊(duì)列,也無阻塞/喚醒機(jī)制。當(dāng)隊(duì)列為空時(shí),線程池中的線程只能睡眠一會兒,然后醒來去看隊(duì)列中有沒有新任務(wù)到來,如此不斷輪詢。
  • 不使用阻塞隊(duì)列,但在隊(duì)列外部,線程池內(nèi)部實(shí)現(xiàn)了阻塞/喚醒機(jī)制
  • 使用阻塞隊(duì)列

很顯然,做法3最完善,既避免了線程池內(nèi)部自己實(shí)現(xiàn)阻塞/喚醒機(jī)制的麻煩,也避免了做法1的睡眠/輪詢帶來的資源消耗和延遲。
現(xiàn)在來帶大家手寫一個(gè)簡單的線程池,讓大家更加理解線程池的工作原理

實(shí)戰(zhàn):手寫簡易線程池

根據(jù)上圖可以知道,實(shí)現(xiàn)線程池需要一個(gè)阻塞隊(duì)列+存放線程的容器

/**
 * Five在努力
 * 自定義線程池
 */
public class ThreadPool {

    /** 默認(rèn)線程池中的線程的數(shù)量 */
    private static final int WORK_NUM = 5;

    /** 默認(rèn)處理任務(wù)的數(shù)量 */
    private static final int TASK_NUM = 100;

    /** 存放任務(wù) */
    private final BlockingQueue<Runnable> taskQueue;

    private final Set<WorkThread> workThreads;//保存線程的集合

    private int workNumber;//線程數(shù)量

    private int taskNumber;//任務(wù)數(shù)量

    public ThreadPool(){
        this(WORK_NUM , TASK_NUM);
    }

    public ThreadPool(int workNumber , int taskNumber) {
        if (taskNumber<=0){
            taskNumber = TASK_NUM;
        }
        if (workNumber<=0){
            workNumber = WORK_NUM;
        }
        this.taskQueue = new ArrayBlockingQueue<Runnable>(taskNumber);
        this.workNumber = workNumber;
        this.taskNumber = taskNumber;

        workThreads = new HashSet<>();

        //工作線程準(zhǔn)備好了
        //啟動一定數(shù)量的線程數(shù),從隊(duì)列中獲取任務(wù)處理
        for (int i=0;i<workNumber;i++) {
            WorkThread workThread = new WorkThread("thead_"+i);
            workThread.start();
            workThreads.add(workThread);
        }
    }

    /**
     * 線程池執(zhí)行任務(wù)的方法,其實(shí)就是往BlockingQueue中添加元素
     * @param task
     */
    public void execute(Runnable task) {
        try {
            taskQueue.put(task);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }


    /**
     * 銷毀線程池
     */
    public void destroy(){
        System.out.println("ready close pool...");
        for (WorkThread workThread : workThreads) {
            workThread.stopWorker();
            workThread = null;//help gc
        }
        workThreads.clear();
    }

    /** 內(nèi)部類,工作線程的實(shí)現(xiàn) */
    private class WorkThread extends Thread{
        public WorkThread(String name){
            super();
            setName(name);
        }
        @Override
        public void run() {
            while (!interrupted()) {
                try {
                    Runnable runnable = taskQueue.take();//獲取任務(wù)
                    if (runnable !=null) {
                        System.out.println(getName()+" ready execute:"+runnable.toString());
                        runnable.run();//執(zhí)行任務(wù)
                    }
                    runnable = null;//help gc
                } catch (Exception e) {
                    interrupt();
                    e.printStackTrace();
                }
            }
        }

        public void stopWorker(){
            interrupt();
        }
    }
}

上面代碼定義了默認(rèn)的線程數(shù)量和默認(rèn)處理任務(wù)數(shù)量,同時(shí)用戶也可以自定義線程數(shù)量和處理任務(wù)數(shù)量。用BlockingQueue阻塞隊(duì)列來存放任務(wù)。用set來存放工作線程,set的好處就不用多說了。懂的都懂

構(gòu)造方法中new對象的時(shí)候,循環(huán)啟動線程,并把線程放入set中。WorkThread實(shí)現(xiàn)Thread,run方法實(shí)現(xiàn)也很簡單,因?yàn)橛幸粋€(gè)stop方法,所以這里需要while判斷,之后從taskQueue隊(duì)列中,獲取任務(wù)。如何獲取不到就阻塞,獲取到的話runnable.run();就執(zhí)行任務(wù),之后把任務(wù)變成null

銷毀線程只需要遍歷set,把每個(gè)線程停止,并且變?yōu)閚ull就行了

執(zhí)行線程任務(wù)execute,只需要從往阻塞隊(duì)列中添加任務(wù)就行了

測試一下:

public class TestMySelfThreadPool {

    private static final int TASK_NUM = 50;//任務(wù)的個(gè)數(shù)

    public static void main(String[] args) {
        ThreadPool myPool = new ThreadPool(3,50);
        for (int i=0;i<TASK_NUM;i++) {
            myPool.execute(new MyTask("task_"+i));
        }

    }

    static class MyTask implements Runnable{

        private String name;
        public MyTask(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }


        @Override
        public void run() {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println("task :"+name+" end...");

        }

        @Override
        public String toString() {
            // TODO Auto-generated method stub
            return "name = "+name;
        }
    }
}

在這里插入圖片描述

結(jié)果ok。沒什么問題

到此這篇關(guān)于java實(shí)現(xiàn)手寫一個(gè)簡單版的線程池的文章就介紹到這了,更多相關(guān)java 手寫線程池內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java數(shù)組轉(zhuǎn)List及Stream的基本方法使用方法

    Java數(shù)組轉(zhuǎn)List及Stream的基本方法使用方法

    Java?的?Stream?流操作是一種簡潔而強(qiáng)大的處理集合數(shù)據(jù)的方式,允許對數(shù)據(jù)進(jìn)行高效的操作,如過濾、映射、排序和聚合,這篇文章主要介紹了Java數(shù)組轉(zhuǎn)List及Stream的基本方法使用教程,需要的朋友可以參考下
    2024-08-08
  • 解決JSONObject.toJSONString()輸出null的問題

    解決JSONObject.toJSONString()輸出null的問題

    這篇文章主要介紹了解決JSONObject.toJSONString()輸出null的問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • Spring如何自定義XML配置擴(kuò)展

    Spring如何自定義XML配置擴(kuò)展

    這篇文章主要介紹了Spring如何自定義XML配置擴(kuò)展,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-12-12
  • SpringBoot如何使用自定義注解實(shí)現(xiàn)接口限流

    SpringBoot如何使用自定義注解實(shí)現(xiàn)接口限流

    這篇文章主要介紹了SpringBoot如何使用自定義注解實(shí)現(xiàn)接口限流,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • Java中的Lock與ReentrantLock深入解析

    Java中的Lock與ReentrantLock深入解析

    這篇文章主要介紹了Java中的Lock與ReentrantLock深入解析,Lock位于java.util.concurrent.locks包下,是一種線程同步機(jī)制,就像synchronized塊一樣,但是,Lock比synchronized塊更靈活、更復(fù)雜,需要的朋友可以參考下
    2024-01-01
  • java工具類StringUtils使用實(shí)例詳解

    java工具類StringUtils使用實(shí)例詳解

    這篇文章主要為大家介紹了java工具類StringUtils使用實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-05-05
  • Java中實(shí)例初始化和靜態(tài)初始化的過程詳解

    Java中實(shí)例初始化和靜態(tài)初始化的過程詳解

    Java代碼初始化塊是Java語言中的一個(gè)非常重要的概念。初始化塊負(fù)責(zé)在創(chuàng)建對象時(shí)進(jìn)行一些必要的操作,例如設(shè)置對象的初始狀態(tài)、初始化成員變量等。初始化塊被分為實(shí)例初始化塊和靜態(tài)初始化塊兩種類型。本文詳細(xì)介紹了初始化的過程,需要的朋友可以參考下
    2023-05-05
  • 一篇文章帶你初步認(rèn)識Maven

    一篇文章帶你初步認(rèn)識Maven

    這篇文章主要為大家初步認(rèn)識了Maven,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-01-01
  • java基礎(chǔ)(System.err和System.out)詳解

    java基礎(chǔ)(System.err和System.out)詳解

    下面小編就為大家?guī)硪黄猨ava基礎(chǔ)(System.err和System.out)詳解。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-06-06
  • 詳細(xì)解讀AbstractStringBuilder類源碼

    詳細(xì)解讀AbstractStringBuilder類源碼

    這篇文章主要介紹了詳細(xì)解讀AbstractStringBuilder類源碼,具有一定參考價(jià)值,需要的朋友可以了解下。
    2017-12-12

最新評論