線程池總結筆記

As everyone knows,線程池在java裏就佔有一定的分量,而這一點在Android上也有很廣泛的應用。曾經無數次被問到過,什麼是線程池,作用是什麼?和線程的關係。是不是感覺頭都大了,今天我就來整理一份關於線程池的一些內容。申明:此爲個人學習總結part

1.什麼是線程池?

理論上來說,線程池其實就是一個管理線程的地方。

2.爲什麼會有線程池這個東西的存在?

在以往的開發中我們需要子線程操作的時候,我們就隨時隨地的new一個Thread,或者弄一個Runnable來開啓一個子線程,如果數量多了,以致於到處都是new的子線程,很多子線程空閒在那裏,有些完成後又被GC,不停的GC,新建和閒置,造成浪費資源,還有可能會造成界面卡頓,對於線程的控制也很混亂。這個時候我們就可以用線程池,用線程池對項目的子線程進行管理和控制。

3.線程池的好處?

(a)線程的複用,重用已經創建好的線程,避免重複的創建和頻繁的GC。

  (b) 控制線程併發數,合理使用系統資源。

  (c)可以有效控制線程的執行。定時執行,取消執行等操作。

探索線程池的用法

我們大概知道了線程池的作用和優點,接下來讓我們瞭解一下它的一些類,一些方法,一些參數的意思。

1.ThreadPoolExecutor:它的構造方法有4種。這裏挑最多參數的那組來說一下,因爲最多的已經包含了其他的構造器裏的參數。參數如下:

<a>corePoolSize 線程池中核心線程的數量

<b>maximumPoolSize 線程池中最大線程數量

<c>keepAliveTime 非核心線程的超時時長。在超過這個時間之後,非核心線程會被回收。若想在超時後回收核心線程,就設置ThreadPoolExecutor的allowCoreThreadTimeOut屬性設置爲true,則這個參數也表示這個核心線程的超時時長。

<c>unit 第三個參數的單位

<d>workQueue 線程池中的任務隊列(和Handler的MessageQueue有點相似),這裏面存儲的都是那些通過ThreadPoolExecutor的execute提交的任務,這些任務是已經提交但是還未執行的那些任務。

<e>threadFactory 爲線程池提供創建新線程的功能。

<f>handler 

 

這個workQueue是一個BlockingQueue類型(阻塞隊列).

而BlockingQueue又有如下類型:

(1)ArrayBlockingQueue:表示規定大小的BlockingQueue,存儲在此的數據是先進先出(FIFO原則)

(2)LinkedBlockingQueue:表示大小不確定的BlockingQueue,LinkedBlockingQueue的構造函數裏面有一個int值,給這個int一個值,那麼代表這個LinkedBlockingQueue是有大小的。如果不給值,默認則是Interger.MAX_VALUE.

(3)priorityBlockingQueue:和LinkedBlockingQueue類似,但是它不是FIFO原則。它是由Comparator來決定存取順序的(比如說按照年齡,身高排序)

(4)synchronousQueue:它是線程安全的BlockingQueue,它內部沒有數據緩存空間。它的理解較爲抽象,我們不能遍歷讀取其中的數據,而是存入和取出的時候會走SynchronousQueue過一下,所以說,在取走的時候這個數據此時纔在隊列裏面存在一下。

你一定還想知道線程放到線程池之後是怎麼去運行的呢?

前提都是在execute一個線程之後.......

(1)線程池的線程數<核心線程數,會立刻啓用一個核心線程去執行

(2)線程池的線程數=核心線程數,而workQueue未滿,則將新線程放入workQueue中等待執行。

(3)線程池的線程數=核心線程數,但是<非核心線程數,而workQueue已滿,則開啓一個非核心線程來執行任務。

(4)線程池的線程數>非核心線程數,則拒絕執行該任務。

接下來介紹幾種線程池的類型

FixedThreadPool:核心線程數固定的線程池。

 

private void mFixedThreadPool(){
    ExecutorService executorService = Executors.newFixedThreadPool(3);
    for(int i=0;i<30;i++){
        Runnable runnable=new Runnable() {
            @Override
            public void run() {
                SystemClock.sleep(3000);

            }
        };
        executorService.execute(runnable);
    }
}

結果是:首先就在覈心線程添加3個任務0,1,2的任務。然後再添加任務在workQueue,若核心線程有空了,就會來處理workQueue任務隊列的任務。

singleThreadPool:核心線程數只有1條。但使用它可以避免去處理線程同步問題。

 

private void mSingleThreadPool(){
    ExecutorService executorService = Executors.newSingleThreadExecutor();
    for(int i=0;i<30;i++){
        Runnable runnable=new Runnable() {
            @Override
            public void run() {
                SystemClock.sleep(3000);

            }
        };
        executorService.execute(runnable);
    }
}

結果是:首先就核心線程添加1個0的任務。然後再添加任務在workQueue裏....

CachedThreadPool:根據程序運行自動調整線程池中的線程數量。最大爲Interger.MAX_VALUE.所以它適合大量任務請求的時候。CachedThreadPool中沒有新任務的時候,裏面的線程會因爲超時而被終止。

 

private void mCachedThreadPool(){
    ExecutorService executorService = Executors.newCachedThreadPool();
    for(int i=0;i<30;i++){
        Runnable runnable=new Runnable() {
            @Override
            public void run() {

            }
        };
        executorService.execute(runnable);
        SystemClock.sleep(3000);//每隔3s在添加新任務。以致於之前的線程又空閒了,所以執行任務的應該都是那一個線程。
    }
}

 

ScheduledThreadPool:具有定時定期執行任務功能的線程池。核心線程數是固定的,但非核心線程數是無窮大的,所以在非核心線程閒置的時候會立即被回收。

(1)延遲啓動任務

 

//延遲啓動任務
private void mDelayScheduledThreadPool(){
    ScheduledExecutorService executorService = Executors.newScheduledThreadPool(3);
        Runnable runnable=new Runnable() {
            @Override
            public void run() {

            }
        };
    executorService.schedule(runnable,2, TimeUnit.SECONDS);
}

(2)延遲定時執行任務

//延遲定時執行任務
private void mTimeScheduledThreadPool(){
    ScheduledExecutorService executorService = Executors.newScheduledThreadPool(3);
    Runnable runnable=new Runnable() {
        @Override
        public void run() {

        }
    };
    executorService.scheduleAtFixedRate(runnable,1,1,TimeUnit.SECONDS);
}

延時1s後,每隔1s執行一個新任務。

(3)延遲執行任務

 

//延遲執行任務
private void mTime2ScheduledThreadPool(){
    ScheduledExecutorService executorService = Executors.newScheduledThreadPool(3);
    Runnable runnable=new Runnable() {
        @Override
        public void run() {

        }
    };
    //第一次延遲1s,以後每次也延遲一秒執行
    executorService.scheduleWithFixedDelay(runnable,1,1,TimeUnit.SECONDS);
}

在線程池裏面還有很多其他的比較常用的方法。

submit:一般情況我們用execute來提交任務,但是有的時候我們還會用到submit,因爲submit有返回值

如下所示,callable接口實現異步任務,在call方法中來執行異步任務,那麼突然要問一句,返回值是什麼呢?你一定會有的懵逼,醬醬醬~其實返回值就是該任務的返回值

你是不是要問我Future是什麼?哎呀,其實Future就是返回結果,返回他的isDone屬性表示異步任務執行成功。

 

private void mSubmint(){
    List<Future<String>> futures=new ArrayList<>();
    ThreadPoolExecutor threadPoolExecutor=new ThreadPoolExecutor(3,5,1,TimeUnit.SECONDS,new LinkedBlockingDeque<Runnable>());
    for(int i=0;i<10;i++){
        Future<String> taskFuture=threadPoolExecutor.submit(new MyTask(i));
        futures.add(taskFuture);
    }

    //遍歷所有任務的結果
    for(Future<String> future:futures){
        try {
            Log.i("mylog","future="+future.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }

}

class MyTask implements Callable<String>{

    private int taskId;

    public MyTask(int taskId) {
        this.taskId = taskId;
    }

    @Override
    public String call() throws Exception {
        SystemClock.sleep(1000);
        //返回每一個任務的執行結果
        return "TaskName="+Thread.currentThread().getName()+"//TaskId="+taskId;
    }
}

除了使用submit可以讓執行的任務有返回值之外,還有一種方式。那就是-----自定義線程池。

自定義線程池,那麼那就是自定義ThreadPoolExecutor.

 

//自定義線程池
private void customThreadPool(View view){
    MyThreadPool myThreadPool=new MyThreadPool(3,5,2000,TimeUnit.SECONDS,new LinkedBlockingDeque<Runnable>());
    for(int i=0;i<10;i++){
        final int finalI=i;
        Runnable runnable=new Runnable() {
            @Override
            public void run() {
                SystemClock.sleep(1000);
                Log.i("myLog","finalId="+finalI);
            }
        };
        myThreadPool.execute(runnable);
    }
}

class MyThreadPool extends ThreadPoolExecutor{

    public MyThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
    }

    @Override
    protected void beforeExecute(Thread t, Runnable r) {
        super.beforeExecute(t, r);
        Log.i("myLog","開始執行任務");
    }

    @Override
    protected void afterExecute(Runnable r, Throwable t) {
        super.afterExecute(r, t);
        Log.i("myLog","任務執行結束");
    }

    @Override
    protected void terminated() {
        super.terminated();
        Log.i("myLog","線程池關閉");
    }
}

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章