您的位置:首页 > 其它

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

2014-03-18 22:15 411 查看
之前展示了如何定义一个执行独立线程的任务。如果你只想一次性运行该任务,这些可能就是你所需要的。如果你想在不同的数据集合重复运行该任务,但是你只想一次只运行一个线程,那么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);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐