Android官方開發文檔Training系列課程中文版:線程執行操作之創建多線程管理器

原文地址:http://android.xsoftlab.net/training/multiple-threads/create-threadpool.html

上節課我們學習瞭如何定義一個任務。如果只是執行單次任務,那麼剛剛所學的已經基本滿足要求了。如果需要針對不同的數據執行同種任務,並且需要同一時間只能執行一項任務,那麼IntentService可能會適合你。如果要使任務隨着資源的可用而執行,或者同一時間需要運行多個任務,那麼就需要專門管理這些線程了。Android系統爲此提供了一個類,那就是傳說中的ThreadPoolExecutor。它可以在線程可用時自動運行隊列中的任務。如果要運行一個任務,只需要將任務添加到隊列中即可。

ThreadPoolExecutor允許多個線程同時進行,所以應當確保代碼是線程安全的。要確保可能會被多個線程訪問到的變量被放在同步代碼塊中。這種方法可以防止一個線程正在讀取一個變量的值,而另一個變量正在對這個變量寫入新值的現象出現。通常情況下,這種現象會發生在靜態變量中,但是也會發生在單例對象上。

定義線程池類

在該類內實例化一個ThreadPoolExecutor對象,並在該類內執行以下工作:

  • 對線程池對象使用靜態變量引用

    在APP內通常只需要一個線程池對象的存在:爲了對CPU資源或網絡資源有一個單一的控制。如果含有不同的Runnable類型,你可能希望對每種類型都創建一個單獨線程池,但是每種類型都還是單例類型。在這裏的例子中,可以添加以下代碼作爲全局屬性聲明。

    public class PhotoManager {
        ...
        static  {
            ...
            // Creates a single static instance of PhotoManager
            sInstance = new PhotoManager();
        }
        ...
  • 使用私有構造方法:
    私有的構造方法可以確保該類只有一個對象存在。

public class PhotoManager {
    ...
    /**
     * Constructs the work queues and thread pools used to download
     * and decode images. Because the constructor is marked private,
     * it's unavailable to other classes, even in the same package.
     */
    private PhotoManager() {
    ...
    }
  • 調用線程池的相關方法啓動任務:
    在線程池類內定義一個可以向線程池隊列中添加任務的方法。

    public class PhotoManager {
    ...
    // Called by the PhotoView to get a photo
    static public PhotoTask startDownload(
        PhotoView imageView,
        boolean cacheFlag) {
        ...
        // Adds a download task to the thread pool for execution
        sInstance.
                mDownloadThreadPool.
                execute(downloadTask.getHTTPDownloadRunnable());
        ...
    }
  • 在構造方法中實例化一個Handler對象,並將其連接到UI線程:Handler允許安全的調用比如View這種UI對象。大多數的UI對象只允許被UI線程訪問。

     private PhotoManager() {
    ...
        // Defines a Handler object that's attached to the UI thread
        mHandler = new Handler(Looper.getMainLooper()) {
            /*
             * handleMessage() defines the operations to perform when
             * the Handler receives a new Message to process.
             */
            @Override
            public void handleMessage(Message inputMessage) {
                ...
            }
        ...
        }
    }

確定線程池參數

如果要實例化ThreadPoolExecutor對象,需要用到以下值:

線程池的初始值以及最大值:

  • 線程數量的初始值用於指定池子的初始大小,最大值代表了該線程池所允許開放的最大併發數量。線程池中的線程數量取決於設備的可用核心數。這個值與當前的設備頗有關係:
public class PhotoManager {
...
    /*
     * Gets the number of available cores
     * (not always the same as the maximum number of cores)
     */
    private static int NUMBER_OF_CORES =
            Runtime.getRuntime().availableProcessors();
}

這個值可能不能夠反映設備的物理核心數量;在一些設備上,核心是否可用取決於系統是否加載。對於這些設備,availableProcessors()返回了當前的活躍核心數量,這個值可能要比真實的總核心數要低。

存活時長及單位

  • 線程在被關閉之間的閒置時長。這個時長由時間單元值負責解釋,這些時間單位常量被定義在類TimeUnit中。

任務隊列

  • 一個持有Runnable對象的隊列。爲了啓動線程中的執行代碼,線程池管理器採用了先進先出的管理原則。在創建線程池之前需要提供一個這樣的隊列,使用任何實現了BlockingQueue接口的類皆可。爲了匹配到APP的要求,你可以選擇適當的隊列實現;學習更多它們的相關知識,請參見ThreadPoolExecutor的描述文檔。這裏的使用了LinkedBlockingQueue:
 public class PhotoManager {
    ...
    private PhotoManager() {
        ...
        // A queue of Runnables
        private final BlockingQueue<Runnable> mDecodeWorkQueue;
        ...
        // Instantiates the queue of Runnables as a LinkedBlockingQueue
        mDecodeWorkQueue = new LinkedBlockingQueue<Runnable>();
        ...
    }
    ...
}

線程池創建

創建一個線程池,只需調用ThreadPoolExecutor()實例化一個線程池管理器就好。它會創建並管理一組線程。因爲線程池大小的初始值與最大值是相同的,所以ThreadPoolExecutor()會在初始化的時候創建出所指定的線程數量:

    private PhotoManager() {
        ...
        // Sets the amount of time an idle thread waits before terminating
        private static final int KEEP_ALIVE_TIME = 1;
        // Sets the Time Unit to seconds
        private static final TimeUnit KEEP_ALIVE_TIME_UNIT = TimeUnit.SECONDS;
        // Creates a thread pool manager
        mDecodeThreadPool = new ThreadPoolExecutor(
                NUMBER_OF_CORES,       // Initial pool size
                NUMBER_OF_CORES,       // Max pool size
                KEEP_ALIVE_TIME,
                KEEP_ALIVE_TIME_UNIT,
                mDecodeWorkQueue);
    }
發佈了73 篇原創文章 · 獲贊 146 · 訪問量 65萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章