1. 程式人生 > >執行緒池 一、executor介面和ExecutorService介面介紹

執行緒池 一、executor介面和ExecutorService介面介紹

工作這麼多年,很少有時間寫部落格,昨天和一個正在跳槽找工作的同學交流,他是做web的,面試的時候被問到了執行緒池一塊的技術,被難住了!這讓我不禁也想鞏固下我這方便的基礎了,天天在用的東西,尤其是像我們這種做網際網路服務端開發的,高併發處理中建立一個優異Thread Pool對執行緒進行復用還是很重要的!俗話說好記性不如爛筆頭,先介紹下Executor介面吧!

為什麼需要建立執行緒池:

(1)因為伺服器如果每一個請求都會建立一個新執行緒,會導致效能上的瓶頸,因為執行緒建立和銷燬都需要jvm不停的處理,如果一個執行緒執行的時間 < (執行緒建立時間+執行緒銷燬的時間)的時候,我們就要考慮執行緒的複用了!

(2)、執行緒數量建立過多,沒有有效的管理,反而起到的是副作用,會大大降低系統的效能的!

(3)、我們要根據具體的業務需求不同,結合作業系統的處理器CPU核數,能夠合理的控制執行緒池大小!選擇不同策略的執行緒池,盲目使用也會帶來一定風險,比如記憶體洩漏,死鎖,併發問題.....

執行緒池的好處:

(1)、降低資源消耗:執行緒複用。

(2)、提高響應速度:有任務的時候,不需要去等待建立執行緒,直接使用已有的執行緒;

(3)、管理:執行緒池對執行緒進行統一分配,調優,監控等等;

一、Executor 介面 (友情提示:不是類Executors)

執行緒與Executor框架執行緒,作業系統各自扮演的角色:任務的2級排程

  java.util.concurrent.Executor: 大部分執行緒池相關的介面都是實現這個介面的

public interface Executor {

    void execute(Runnable command);

}

 他的子介面和實現的類如下:

​​​

完整的Executor介面繼承實現結構圖如下:

我們重點看我圈出來的不分,基本就是你學習執行緒池這塊要反覆看的內容;

我們繼續順著原始碼往下分析:(綠色實線箭頭是繼承,虛線是介面實現)

1、ExecutorService:servirce顧名思義是提供服務的介面。

【首先申明executor架構下的ForkJoinPool思想和其他的介面類不一樣,ForkJoinPool的優勢在於,可以充分利用多cpu,多核cpu的優勢,把一個任務拆分成多個“小任務”,把多個“小任務”放到多個處理器核心上並行執行;當多個“小任務”執行完成之後,再將這些執行結果合併起來;(後續具體介紹ForkJoinPool用法)】;

(1)shutdown: 具體原始碼實現是:

public void shutdown() {

        final ReentrantLock mainLock = this.mainLock;

        mainLock.lock();

        try {

        //想操作shutdownshutdownnow許可權check ModifyThread許可權通過

            checkShutdownAccess();

       //runstate設為給定的目標

            advanceRunState(SHUTDOWN);

    //中斷一些正在等待任務的的空閒的執行緒,

            interruptIdleWorkers();

//取消和清楚,由於shutdown策略中所有不應該繼續執行的工作佇列

            onShutdown(); // hook for ScheduledThreadPoolExecutor

        } finally {

            mainLock.unlock();

        }

        tryTerminate();

    }

下面我謝的一個簡單的test:

總結:shutdown 呼叫之後,執行緒池拒絕接受新submit的任務,但是會繼續執行在shutdown之前的任務;

(2)、shutdownNow:原始碼相似,他是停止正在執行的任務,返回空閒的執行緒,並且拒絕接受新的任務

(3)、isShutdown():當前executor是否已經shutdown

(4)、isTerminated();若關閉後所有任務都已完成,則返回true。注意除非首先呼叫shutdown或shutdownNow,否則isTerminated永不為true;

(6)、submit():提交新的任務,任務分Runnable和Callable型別

(7)、invokeAll()和invokeAny(),在批量執行或多選一的業務場景中非常方便。invokeAll()在所有任務都完成(包括成功/被中斷/超時)後才會返回,invokeAny()在任意一個任務成功(或ExecutorService被中斷/超時)後就會返回。

package com.executor.test;

import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Description:
 * User: ZhuRong
 * Date: 2018-07-20  13:18
 */
public class ShutDowmTest {
    static int index = 1;
    public static void main(String[] args) {
        try {
            //建立一個執行緒池,可以同一時間容乃3條執行緒
            ExecutorService executorService = Executors.newFixedThreadPool(3);
            for (int i = 0; i < 5; i++) {
                executorService.submit(new AutoIncressNum());
            }
            Thread.sleep(2000L);
            executorService.shutdown();
            for (int i = 0; i < 3; i++) {
                executorService.submit(new AutoIncressNum());
            }
            System.out.println(executorService.isShutdown());
            System.out.println(executorService.isTerminated());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    static class AutoIncressNum implements Runnable {
        @Override
        public void run() {
            try {
                Random random = new Random();
                Thread.sleep(1000L + random.nextInt(5000));
                System.out.println(Thread.currentThread().getName()+":"+index);
                index++;
            } catch (Exception e) {
                System.out.println(Thread.currentThread().getName() + " Interrupted!");
                e.printStackTrace();
            }

        }
    }
}

package com.executor.test;

import java.util.List;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Description:
 * User: ZhuRong
 * Date: 2018-07-20  13:18
 */
public class ShutDownNowTest {
    static int index = 1;
    public static void main(String[] args) {
        try {
            //建立一個執行緒池,可以同一時間容乃3條執行緒
            ExecutorService executorService = Executors.newFixedThreadPool(3);
            for (int i = 0; i < 5; i++) {
                executorService.submit(new AutoIncressNum());
            }
            Thread.sleep(2000L);
            List<Runnable> list =  executorService.shutdownNow();
            System.out.println(executorService.isShutdown());
            System.out.println(executorService.isTerminated());
            for(Runnable l: list){
                System.out.println(l.toString());
            }
            for (int i = 0; i < 2; i++) {
                executorService.submit(new AutoIncressNum());
            }

        } catch (Exception e) {
//            e.printStackTrace();
        }
    }

    static class AutoIncressNum implements Runnable {
        @Override
        public void run() {
            try {
                Random random = new Random();
                Thread.sleep(1000L + random.nextInt(5000));
                System.out.println(Thread.currentThread().getName()+":"+index);
                index++;
            } catch (Exception e) {
                System.out.println(Thread.currentThread().getName() + " Interrupted!");
                e.printStackTrace();
            }

        }
    }
}

先介紹這2個介面,後面有時間繼續介紹其他的執行緒池相關的介面和類!這個測試案例建議和大家還是跑一跑就懂了ExecutorService這一個介面的裡面的api應用了!