多线程之二:创建一个多线程管理器(Creating a manager for Multiple Threads)

之前展示了如何定义一个执行独立线程的任务。如果你只想一次性运行该任务,这些可能就是你所需要的。如果你想在不同的数据集合重复运行该任务,但是你只想一次只运行一个线程,那么IntentService符合你的要求。为自动运行任务的资源可用,为了允许多任务同时执行,你需要提供一个可管理的线程集合。为实现这些,可利用一个ThreadPoolExecutor实例,当一个线程在它的线程池中被释放它就执行队列中的另一个任务。为了运行该任务,你只需要把任务加入到队列中。

一个线程池可以执行一个任务的多个并行实例,所以你应该确保你的代码线程安全的。在同步块中的封闭变量可以被多个线程同时执行。该方法可以阻止一个线程读取变量当另外一个线程在写该变量时。具有代表性地是,这种情况出现静态变量,但是它也出现在其他之实例化一次的对象中。学习更多关于这些的知识,请阅读Processes and Threads API指导。

定义线程池类

在自己的类中实例化ThreadPoolExecutor对象。这个类,实现如下所示:

线程池使用静态变量:

为了获取有限的CPU或者网络资源的单一控制权点,你的app可能只需要一个单独的线程实例。如果你有不同的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,并把它关联到你的app的主线程。

一个Handler允许你的app安全地调用UI对象的方法例如View对象。大多数的UI对象只可以在主线程中安全地被修改。该方法在Communicate with the UI Thread一章中被详细地描述了。例如:

 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();
}

这个数量不可以反映设备的物理内核数量;一些设备拥有未激活的一个或多个内核的CPUs,这些取决于系统的加载。对于这些设备来说,availableProcessors() 方法可以 返回激活的内核数,这个数字可能小于全部内核的数量。

保持存活时间和时间单元

持续时间是一个线程从保持空闲到关闭之前。持续时间被时间单元值解读,其中一个常量定义为TimeUnit。

任务队列

ThreadPoolExecutor中的输入队列取走Runnable对象。 为了在一个线程中执行代码,线程池管理器按照先进先出的原则取走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);
    }


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值