Java線程<第五篇>:線程池

utils包提供開了 ExecutorService 線程池的實(shí)現(xiàn)义矛,主要目的是為了重復(fù)利用線程,提高系統(tǒng)效率。
Thread是一個(gè)重量級(jí)的資源俐银,創(chuàng)建、啟動(dòng)以及銷毀都是比較耗費(fèi)系統(tǒng)資源的端仰,因此使用線程池來管理線程是一個(gè)非常重要的編程習(xí)慣捶惜。

1、Thread
    new Thread(new Runnable() {
        @Override
        public void run() {

        }
    }).start();

直接使用 Thread 的弊端如下:

  • 每次new Thread新建對(duì)象性能差荔烧。
  • 線程缺乏統(tǒng)一管理吱七,可能無限制新建線程,相互之間競(jìng)爭(zhēng)鹤竭,及可能占用過多系統(tǒng)資源導(dǎo)致死機(jī)或oom踊餐。
  • 缺乏更多功能,如定時(shí)執(zhí)行臀稚、定期執(zhí)行吝岭、線程中斷。
2吧寺、線程池(ExecutorService窜管、ThreadPool)
(1)newCachedThreadPool

創(chuàng)建一個(gè)可緩存線程池,如果線程池長(zhǎng)度超過處理需要稚机,可靈活回收空閑線程幕帆,若無可回收,則新建線程

    ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
    for (int i = 0; i < 10; i++) {
        final int index = i;
        try {
            Thread.sleep(index * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        cachedThreadPool.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(index);
            }
        });
    }
    cachedThreadPool.shutdown();

線程池為無限大赖条,當(dāng)執(zhí)行第二個(gè)任務(wù)時(shí)第一個(gè)任務(wù)已經(jīng)完成失乾,會(huì)復(fù)用執(zhí)行第一個(gè)任務(wù)的線程常熙,而不用每次新建線程。

(2)newFixedThreadPool

創(chuàng)建一個(gè)定長(zhǎng)線程池仗扬,可控制線程最大并發(fā)數(shù)症概,超出的線程會(huì)在隊(duì)列中等待

    ExecutorService cachedThreadPool = Executors.newFixedThreadPool(5);
    for (int i = 0; i < 10; i++) {
        final int index = i;
        try {
            Thread.sleep(index * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        cachedThreadPool.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println(index);
            }
        });
    }
    cachedThreadPool.shutdown();

這里支持的最大線程數(shù)是5, 也可以根據(jù)系統(tǒng)而定早芭,獲取系統(tǒng)可被利用的進(jìn)程數(shù)

Runtime.getRuntime().availableProcessors()
(3)newScheduledThreadPool

創(chuàng)建一個(gè)定長(zhǎng)線程池彼城,支持定時(shí)及周期性任務(wù)執(zhí)行。

定義線程池退个,最大線程數(shù)是5

    ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);

延遲執(zhí)行:

    scheduledThreadPool.schedule(new Runnable() {

        @Override
        public void run() {
            System.out.println("delay");
        }
    }, 3, TimeUnit.SECONDS);

延遲1秒募壕,并每隔3秒定期執(zhí)行

    scheduledThreadPool.scheduleAtFixedRate(new Runnable() {

        @Override
        public void run() {
            System.out.println("delay 1 seconds, and excute every 3 seconds");
        }
    }, 1, 3, TimeUnit.SECONDS);

關(guān)于延遲執(zhí)行和周期性執(zhí)行我們還會(huì)想到Timer

    Timer timer = new Timer();
    TimerTask timerTask = new TimerTask() {
        @Override
        public void run() {
            
        }
    };
    timer.schedule(timerTask, 1000, 3000);
(4)newSingleThreadExecutor

創(chuàng)建一個(gè)單線程化的線程池,它只會(huì)用唯一的工作線程來執(zhí)行任務(wù)语盈,保證所有任務(wù)按照指定順序(FIFO, LIFO, 優(yōu)先級(jí))執(zhí)行舱馅。

    ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
    for (int i = 0; i < 10; i++) {
        final int index = i;
        singleThreadExecutor.execute(new Runnable() {

            @Override
            public void run() {
                try {
                    System.out.println(index);
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
    }

Java提供的四種線程池的優(yōu)點(diǎn)

  • 重用存在的線程,減少對(duì)象創(chuàng)建刀荒、消亡的開銷代嗤,性能佳。
  • 可有效控制最大并發(fā)線程數(shù)缠借,提高系統(tǒng)資源的使用率干毅,同時(shí)避免過多資源競(jìng)爭(zhēng),避免堵塞泼返。
  • 提供定時(shí)執(zhí)行硝逢、定期執(zhí)行、單線程绅喉、并發(fā)數(shù)控制等功能渠鸽。
(5)自定義線程池

如果我們不想使用以上4種線程池,可以自定義一個(gè)線程池:

/**
 * 線程池
 */
public class DefaultPoolExecutor {

    private static final ThreadFactory sThreadFactory = new ThreadFactory() {

        private final AtomicInteger mCount = new AtomicInteger(1);

        @Override
        public Thread newThread(Runnable runnable) {
            // 線程
            return new Thread(runnable, "ThreadName #" + mCount.getAndIncrement());
        }
    };


    // 可用處理器的Java虛擬機(jī)的數(shù)量
    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
    // 最大線程數(shù)(最佳線程數(shù) = CPU_COUNT + 1)
    private static final int MAX_CORE_POOL_SIZE = CPU_COUNT + 1;
    //空閑時(shí)間達(dá)到 30s 時(shí)柴罐,回收空閑線程(每隔30s回收一次)
    private static final long THREAD_TIMEOUT = 30L;

    /**
     * 新建一個(gè)線程池
     * 每個(gè)線程都會(huì)消耗大概1M的內(nèi)存徽缚,使用線程池管理和復(fù)用線程
     *
     * @param corePoolSize 線程池大小
     * @return
     */
    public static ThreadPoolExecutor newDefaultPoolExecutor(int corePoolSize) {
        if (corePoolSize == 0) {
            return null;
        }
        corePoolSize = Math.min(corePoolSize, MAX_CORE_POOL_SIZE);
        int maximumPoolSize = corePoolSize;
        // corePoolSize: 當(dāng)線程池小于corePoolSize時(shí),新提交任務(wù)將創(chuàng)建一個(gè)新線程執(zhí)行任務(wù)革屠,即使此時(shí)線程池中存在空閑線程
        // 當(dāng)線程池達(dá)到corePoolSize時(shí)凿试,新提交任務(wù)將被放入workQueue中,等待線程池中任務(wù)調(diào)度執(zhí)行
        // 當(dāng)workQueue已滿屠阻,且maximumPoolSize>corePoolSize時(shí)红省,新提交任務(wù)會(huì)創(chuàng)建新線程執(zhí)行任務(wù)
        // 當(dāng)提交任務(wù)數(shù)超過maximumPoolSize時(shí),新提交任務(wù)由RejectedExecutionHandler處理
        // 當(dāng)線程池中超過corePoolSize線程国觉,空閑時(shí)間達(dá)到keepAliveTime時(shí)吧恃,關(guān)閉空閑線程
        // 當(dāng)設(shè)置allowCoreThreadTimeOut(true)時(shí),線程池中線程空閑時(shí)間達(dá)到keepAliveTime也將關(guān)閉
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, THREAD_TIMEOUT,
            TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(64), sThreadFactory);
        threadPoolExecutor.allowCoreThreadTimeOut(true);
        return threadPoolExecutor;
    }

}

擴(kuò)充:

除了execute可以執(zhí)行線程池中的線程之外麻诀,submit也是可以的

圖片.png

submit的效果和execute是一樣的痕寓,只是execute沒有返回值傲醉,而submit有返回值。

(1)Future<?> submit(Runnable task)
        Future future1 = singleThreadExecutor.submit(new Runnable() {
            @Override
            public void run() {

            }
        });
(2)<T> Future<T> submit(Runnable task, T result)
        Future<String> future = singleThreadExecutor.submit(new Runnable() {
            @Override
            public void run() {

            }
        }, "A");
(3)<T> Future<T> submit(Callable<T> task);
    Callable callable = new Callable<String>() {

        @Override
        public String call() throws Exception {
            return "A";
        }
    };


    Future<String> future = singleThreadExecutor.submit(callable);

如果Future中有值的話可以通過以下代碼獲取

        try {
            System.out.println(future.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

Future的其余操作如圖

圖片.png

[本章完...]

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末呻率,一起剝皮案震驚了整個(gè)濱河市硬毕,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌礼仗,老刑警劉巖吐咳,帶你破解...
    沈念sama閱讀 218,607評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異元践,居然都是意外死亡韭脊,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門单旁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來沪羔,“玉大人,你說我怎么就攤上這事象浑∧枋危” “怎么了?”我有些...
    開封第一講書人閱讀 164,960評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵愉豺,是天一觀的道長(zhǎng)篓吁。 經(jīng)常有香客問我,道長(zhǎng)粒氧,這世上最難降的妖魔是什么越除? 我笑而不...
    開封第一講書人閱讀 58,750評(píng)論 1 294
  • 正文 為了忘掉前任节腐,我火速辦了婚禮外盯,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘翼雀。我一直安慰自己饱苟,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,764評(píng)論 6 392
  • 文/花漫 我一把揭開白布狼渊。 她就那樣靜靜地躺著箱熬,像睡著了一般。 火紅的嫁衣襯著肌膚如雪狈邑。 梳的紋絲不亂的頭發(fā)上城须,一...
    開封第一講書人閱讀 51,604評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音米苹,去河邊找鬼糕伐。 笑死,一個(gè)胖子當(dāng)著我的面吹牛蘸嘶,可吹牛的內(nèi)容都是我干的良瞧。 我是一名探鬼主播陪汽,決...
    沈念sama閱讀 40,347評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼褥蚯!你這毒婦竟也來了挚冤?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,253評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤赞庶,失蹤者是張志新(化名)和其女友劉穎训挡,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體歧强,經(jīng)...
    沈念sama閱讀 45,702評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡舍哄,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,893評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了誊锭。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片表悬。...
    茶點(diǎn)故事閱讀 40,015評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖丧靡,靈堂內(nèi)的尸體忽然破棺而出蟆沫,到底是詐尸還是另有隱情,我是刑警寧澤温治,帶...
    沈念sama閱讀 35,734評(píng)論 5 346
  • 正文 年R本政府宣布饭庞,位于F島的核電站,受9級(jí)特大地震影響熬荆,放射性物質(zhì)發(fā)生泄漏舟山。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,352評(píng)論 3 330
  • 文/蒙蒙 一卤恳、第九天 我趴在偏房一處隱蔽的房頂上張望累盗。 院中可真熱鬧,春花似錦突琳、人聲如沸若债。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,934評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蠢琳。三九已至,卻和暖如春镜豹,著一層夾襖步出監(jiān)牢的瞬間傲须,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,052評(píng)論 1 270
  • 我被黑心中介騙來泰國打工趟脂, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留泰讽,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,216評(píng)論 3 371
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像菇绵,于是被迫代替她去往敵國和親肄渗。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,969評(píng)論 2 355

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