Android之線程池深度剖析

 

Android之線程池深度剖析

標籤: Android多線程線程池ThreadPoolExecutor
 1872人閱讀 評論(5) 收藏 舉報
 分類:

1.線程池的引入


引入的好處

1)提升性能(創建和消耗對象費時費CPU資源);
2)防止內存過度消耗(控制活動線程的數量,防止併發線程過多);

使用條件

Android中當同時併發多個網絡線程時,引入線程池技術會極大地提高APP的性能。

例如:多線程下載,點一個下載一個(假設允許最多同時下載五個),當點到第六個的時候開始等待,這就涉及到線程的管理



2.封裝線程池管理者

1)jdk自身帶有線程池的實現類ThreadPoolExecutor


2)ThreadPoolManager是基於ThreadPoolExecutor進行了封裝的類

其中,獲取當前可用的處理器核心數我們用Runtime.getRuntime().availableProcessors(),我們來看它的註釋:


[java] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. package com.example.threadpooldemo;


    import java.util.concurrent.Executors;
    import java.util.concurrent.LinkedBlockingQueue;
    import java.util.concurrent.ThreadPoolExecutor;
    import java.util.concurrent.TimeUnit;


    /**
     * 線程池管理
     * 管理整個項目中所有的線程,所以不能有多個實例對象
     */
    public class ThreadPoolManager {
    /**
    * 單例設計模式(餓漢式)
    * 單例首先私有化構造方法,然後餓漢式一開始就開始創建,並提供get方法
    */
    private static ThreadPoolManager mInstance = new ThreadPoolManager();
    public static ThreadPoolManager getInstance() {
    return mInstance;
    }


    private int corePoolSize;//核心線程池的數量,同時能夠執行的線程數量
    private int maximumPoolSize;//最大線程池數量,表示當緩衝隊列滿的時候能繼續容納的等待任務的數量
    private long keepAliveTime = 1;//存活時間
    private TimeUnit unit = TimeUnit.HOURS;
    private ThreadPoolExecutor executor;
    private ThreadPoolManager() {
    /**
    * 給corePoolSize賦值:當前設備可用處理器核心數*2 + 1,能夠讓cpu的效率得到最大程度執行(有研究論證的)
    */
    corePoolSize = Runtime.getRuntime().availableProcessors()*2+1;
    maximumPoolSize = corePoolSize;//雖然maximumPoolSize用不到,但是需要賦值,否則報錯
    executor = new ThreadPoolExecutor(
    corePoolSize, //當某個核心任務執行完畢,會依次從緩衝隊列中取出等待任務
    maximumPoolSize, //5,先corePoolSize,然後new LinkedBlockingQueue<Runnable>(),然後maximumPoolSize,但是它的數量是包含了corePoolSize的
    keepAliveTime,//表示的是maximumPoolSize當中等待任務的存活時間
    unit, 
    new LinkedBlockingQueue<Runnable>(),//緩衝隊列,用於存放等待任務,Linked的先進先出
    Executors.defaultThreadFactory(),//創建線程的工廠
    new ThreadPoolExecutor.AbortPolicy()//用來對超出maximumPoolSize的任務的處理策略
    );
    }
    /**
    * 執行任務
    */
    public void execute(Runnable runnable){
    if(runnable==null)return;

    executor.execute(runnable);
    }
    /**
    * 從線程池中移除任務
    */
    public void remove(Runnable runnable){
    if(runnable==null)return;

    executor.remove(runnable);
    }

    }

1>ThreadPoolExecutor說明文檔:

ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler)

corePoolSize: 核心線程數,能夠同時執行的任務數量;
maximumPoolSize:除去緩衝隊列中等待的任務,最大能容納的任務數(其實是包括了核心線程池數量);
keepAliveTime:超出workQueue的等待任務的存活時間,就是指maximumPoolSize裏面的等待任務的存活時間;
unit:時間單位;
workQueue:阻塞等待線程的隊列,一般使用new LinkedBlockingQueue<Runnable>()這個,如果不指定容量,會一直往裏邊添加,沒有限制,workQueue永遠不會滿;
threadFactory:創建線程的工廠,使用系統默認的類;
handler:當任務數超過maximumPoolSize時,對任務的處理策略,默認策略是拒絕添加;
2>執行流程:

當線程數小於corePoolSize時,每添加一個任務,則立即開啓線程執行;當corePoolSize滿的時候,後面添加的任務將放入緩衝隊列workQueue等待;當workQueue也滿的時候,看是否超過maximumPoolSize線程數,如果超過,默認拒絕執行。
3>舉例說明:
假如corePoolSize=2,maximumPoolSize=3,workQueue容量爲8;最開始,執行的任務A,B,此時corePoolSize已用完,再次執行任務C,則C將被放入緩衝隊列workQueue中等待着,如果後來又添加了7個任務,此時workQueue已滿,則後面再來的任務將會和maximumPoolSize比較,由於maximumPoolSize爲3,所以只能容納1個了,因爲有2個在corePoolSize中運行了,所以後面來的任務默認都會被拒絕。


3)Runnable與線程的區別
Runnable只是一個接口,它的源碼如下,而線程是真正開啓系統資源去執行任務,他們兩個,線程是真正消耗系統資源的
[java] view plain copy
 在CODE上查看代碼片派生到我的代碼片
    1. /* 
    2.  *  Licensed to the Apache Software Foundation (ASF) under one or more 
    3.  *  contributor license agreements.  See the NOTICE file distributed with 
    4.  *  this work for additional information regarding copyright ownership. 
    5.  *  The ASF licenses this file to You under the Apache License, Version 2.0 
    6.  *  (the "License"); you may not use this file except in compliance with 
    7.  *  the License.  You may obtain a copy of the License at 
    8.  * 
    9.  *     http://www.apache.org/licenses/LICENSE-2.0 
    10.  * 
    11.  *  Unless required by applicable law or agreed to in writing, software 
    12.  *  distributed under the License is distributed on an "AS IS" BASIS, 
    13.  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
    14.  *  See the License for the specific language governing permissions and 
    15.  *  limitations under the License. 
    16.  */  
    17.   
    18. package java.lang;  
    19.   
    20.   
    21. /** 
    22.  * Represents a command that can be executed. Often used to run code in a 
    23.  * different {@link Thread}. 
    24.  */  
    25. public interface Runnable {  
    26.   
    27.     /** 
    28.      * Starts executing the active part of the class' code. This method is 
    29.      * called when a thread is started that has been created with a class which 
    30.      * implements {@code Runnable}. 
    31.      */  
    32.     public void run();  
    33. }  


3.線程池例子


下面是一個線程池的例子(演示多線程執行任務),以加深對原理的理解

1)引入我們封裝好的ThreadPoolManager.Java


2)演示功能

[java] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. package com.example.threadpooldemo;


    import android.app.Activity;
    import android.os.Bundle;
    import android.os.SystemClock;
    import android.util.Log;


    /**
     * 演示線程池
     *
     */
    public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    /**
    * 創建九個任務
    */
    for (int i = 0; i < 9; i++) {
    ThreadPoolManager.getInstance().execute(new DownloadTask(i));
    }
    }
    /**
    * 模仿下載任務,實現Runnable
    */
    class DownloadTask implements Runnable{
    private int num;
    public DownloadTask(int num) {
    super();
    this.num = num;
    Log.d("JAVA", "task - "+num + " 等待中...");
    }
    @Override
    public void run() {
    Log.d("JAVA", "task - "+num + " 開始執行了...開始執行了...");
    SystemClock.sleep(5000); //模擬延時執行的時間
    Log.e("JAVA", "task - "+num + " 結束了...");
    }
    }


    }


打印結果如下:



項目源碼,點擊下載

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