Creating a Manager for Multiple Threads_翻译
The previous lesson showed how to define a task that executes on a separate thread. If you only want to run the task once, this may be all you need. If you want to run a task repeatedly on different sets of data, but you only need one execution running at a time, an IntentService suits your needs. To automatically run tasks as resources become available, or to allow multiple tasks to run at the same time (or both), you need to provide a managed collection of threads. To do this, use an instance of ThreadPoolExecutor, which runs a task from a queue when a thread in its pool becomes free. To run a task, all you have to do is add it to the queue.
上一篇教程向您展示了如何在一个独立的线程中执行一个任务。你大多数情况下,只想运行一次这个任务。如果你想要在不同的数据集上重复运行一个任务,但是在应用运行的时候,你需要执行一次,那么,IntentService是你不错的选择。为了当资源变得可用时以自动运行任务,或者允许多个任务同时运行,你需要提供一个受到管理的线程集。为了做到这一点,使用ThreadPoolExecutor的实例吧,它允许它的线程池中一个线程变得可用时,从一个队列中取出一个任务,然后交给这个可用的线程去执行。为了运行一个任务,你需要做的就是将这个任务添加到队列中。似乎一个线程池有一个任务队列,不断地往队列中添加任务,当线程池中的线程可用时,从队列中取出任务,在这个线程上执行。自己创建一个线程池,并且维护一个队列。
A thread pool can run multiple parallel instances of a task, so you should ensure that your code is thread-safe. Enclose variables that can be accessed by more than one thread in asynchronized block. This approach will prevent one thread from reading the variable while another is writing to it. Typically, this situation arises with static variables, but it also occurs in any object that is only instantiated once. To learn more about this, read the Processes and Threads API guide.
一个线程池可以并行运行一个任务的多个实例,所以你要保证你的代码是线程安全的。在一个同步中,关闭能够被一个以上的线程访问到的变量,这一点可以保证当一个线程在写数据到变量中时,能够阻止另外一个线程读取这个变量。典型的,这种读写冲突的现象在静态变量上尤为显著,然后,对于任何单例的对象,也适用。也即是要注意多线程之间的同步。既然用到了线程池,难免会涉及线程之间的同步问题。
Define the Thread Pool Class
Instantiate ThreadPoolExecutor in its own class. Within this class, do the following:
初始化ThreadPoolExecutor,要做的事情有以下几个:
- Use static variables for thread pools
- 将线程池声明为静态变量
- You may only want a single instance of a thread pool for your app, in order to have a single control point for restricted CPU or network resources. If you have different
Runnabletypes, you may want to have a thread pool for each one, but each of these can be a single instance. For example, you can add this as part of your global field declarations: - 为了对有限的CPU资源或者网络资源有一个单独的控制点,你也许需要为你的应用设置一个线程池的单例,如果你有不同的runnable类型,那么你也许想要为每个这样的类型搞一个线程池,比如,你可以加入作为你的全局域的声明:不同的runnable类型是指由下载任务,有解码任务等。每种类型的任务都可以有自己的线程池来执行。
public class PhotoManager {
...
static {
...
// Creates a single static instance of PhotoManager
sInstance = new PhotoManager();
}
...Use a private constructor
使用一个私有的构造器
Making the constructor private ensures that it is a singleton, which means that you don't have to enclose accesses to the class in a
synchronizedblock:使得构造器私有,可以保证单例模式,这也就是意味着在一个同步操作中,你不必关闭对该类的访问。
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() {
...
在这里构建线程池以及工作队列。下载线程池就对应着下载任务队列;解码图片线程池就对应着解码图片任务队列。
}Start your tasks by calling methods in the thread pool class.
Define a method in the thread pool class that adds a task to a thread pool's queue. For example:
通过调用线程池类的方法,来启动你的任务。在线程池类中定义一个方法,该方法可以添加一个任务到线程池的队列中。例如:
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());
...
}整个应用通过sInstance这一个单例模式,来调用mDownloadThreadPool这个下载线程池,并且调用execute方法来添加一个下载任务到下载线程池的工作队列。threadpooledecuter可以看成是一个线程池,executer方法就是添加任务到队列。
Instantiate a
Handlerin the constructor and attach it to your app's UI thread.A
Handlerallows your app to safely call the methods of UI objects such asViewobjects. Most UI objects may only be safely altered from the UI thread. This approach is described in more detail in the lessonCommunicate with the UI Thread. For example:在构造器中初始化一个句柄,并且将这个句柄附加到你的主线程中。一个句柄允许你的应用能够安全调用UI对象的方法,比如View对象。只有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) {
...
}
...
}
}Determine the Thread Pool Parameters
Once you have the overall class structure, you can start defining the thread pool. To instantiate a
ThreadPoolExecutorobject, you need the following values:一旦你对类的结构有一个大体的了解,你可以开始定义线程池了。为了初始化一个
ThreadPoolExecutor对象,你需要下列的值:- Initial pool size and maximum pool size
- 初始化线程池的大小和最大的线程池大小
- The initial number of threads to allocate to the pool, and the maximum allowable number. The number of threads you can have in a thread pool depends primarily on the number of cores available for your device. This number is available from the system environment:
- 允许分配到池中的线程个数,以及允许的最大分配个数。你在一个线程池中拥有的线程的个数依赖于你的设备的核数。这个数字可以从系统环境中获取。
-
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();
}This number may not reflect the number of physical cores in the device; some devices have CPUs that deactivate one or more cores depending on the system load. For these devices,
availableProcessors()returns the number of active cores, which may be less than the total number of cores.这个数字也许与实际的核数有出入。一些设备的CPU会根据系统的负载来熄灭一个或者几个核。对于这些设备,
availableProcessors方法只是返回激活的核数,可能小于本应该有的核数。也就是说,能够为线程池分配多少个线程,依赖于设备的核数,而设备的核数可以通过availableProcessors方法来获取,这个方法获取的仅仅是激活的核数,而不是所有的核数。Keep alive time and time unit
The duration that a thread will remain idle before it shuts down. The duration is interpreted by the time unit value, one of the constants defined in
TimeUnit.在一个线程结束前的空闲时间时长。这个时长由time unit值来解释,这个时长在TimeUnit中定义,是其中的一个常量。
A queue of tasks
The incoming queue from which
ThreadPoolExecutortakesRunnableobjects. To start code on a thread, a thread pool manager takes aRunnableobject from a first-in, first-out queue and attaches it to the thread. You provide this queue object when you create the thread pool, using any queue class that implements theBlockingQueueinterface. To match the requirements of your app, you can choose from the available queue implementations; to learn more about them, see the class overview forThreadPoolExecutor. This example uses theLinkedBlockingQueueclass:一个队列,在该队列中,
ThreadPoolExecutor取回runnable对象。为了启动一个线程中的代码,线程池管理者在队列中取回一个runnable对象给线程。当你创建了线程池时,你是使用的实现了BlockingQueue接口的队列类来提供一个队列。为了满足你的应用的需求,你可以使用可用的队列实现,似乎是系统已经做好的。这个例子使用了LinkedBlockingQueue类。该类实现了BlockingQueue接口。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>();
...
}
...
}Create a Pool of Threads
To create a pool of threads, instantiate a thread pool manager by calling
)">ThreadPoolExecutor(). This creates and manages a constrained group of threads. Because the initial pool size and the maximum pool size are the same,ThreadPoolExecutorcreates all of the thread objects when it is instantiated. For example:为了创建线程池,调用
)">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);
}
Creating a Manager for Multiple Threads_翻译的更多相关文章
- Android 性能优化(16)线程优化:Creating a Manager for Multiple Threads 如何创建一个线程池管理类
Creating a Manager for Multiple Threads 1.You should also read Processes and Threads The previous le ...
- Sending Operations to Multiple Threads_翻译
The speed and efficiency of a long-running, data-intensive operation often improves when you split i ...
- Got error creating database manager: java.io.IOException解决方法
14/03/26 23:03:55 ERROR tool.BaseSqoopTool: Got error creating database manager: java.io.IOException ...
- Supporting Multiple Screens 翻译 支持各种屏幕(上)
Supporting Multiple Screens 支持各种各样的屏幕尺寸.屏幕密度 Android runs on a variety of devices that offer differe ...
- Umbraco(5)-Creating Master Template Part 1(翻译文档)
原文地址:http://www.ncloud.hk/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/umbraco5-creating-master-template-par ...
- Android Training
Building Apps with Content Sharing Simple Data --> Intent && ActionProvider 介绍如何让应用程序共享简单 ...
- Android 线程池系列教程(3) 创建线程池
Creating a Manager for Multiple Threads 上一课 下一课 1.This lesson teaches you to Define the Thread Pool ...
- Android 线程池系列教程(1)目录
Sending Operations to Multiple Threads 1.Dependencies and prerequisites Android 3.0 (API Level 11) o ...
- Linux学习-逻辑滚动条管理员 (Logical Volume Manager)
LVM 可以整合多个实体 partition 在一起, 让这些 partitions 看起来就像是一个磁盘一样!而且,还可以在未来新增或移除其他的实 体 partition 到这个 LVM 管理的磁盘 ...
随机推荐
- Win8 Metro(C#)数字图像处理--2.63图像指数增强
原文:Win8 Metro(C#)数字图像处理--2.63图像指数增强 [函数名称] 指数增强 WriteableBitmap IndexenhanceProcess(Writea ...
- linux服务脚本编写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 3 ...
- C#添加应用路径到系统PATH变量
var dllDirectory = @"C:/some/path"; Environment.SetEnvironmentVariable("PATH", E ...
- python 动态调用模块&类&方法
转载自:http://www.cnblogs.com/bluefrog/archive/2012/05/11/2496439.html 一直想知道python里有没有类似php中的 $classnam ...
- 改善C#程序的建议7:正确停止线程
原文:改善C#程序的建议7:正确停止线程 开发者总尝试对自己的代码有更多的控制.“让那个还在工作的线程马上停止下来”就是诸多要求中的一种.然而事与愿违,这里面至少存在两个问题: 第一个问题是:正如线程 ...
- eval 未将对象引用到对象实例
1.Eval("No") == null ? "" : Convert.ToString(Eval("NO"))
- javascript 实现ajax
AJAX 英文名称 Asynchronous JavaScript and XML即异步的 JavaScript 和 XML AJAX 是与服务器交换数据并更新部分网页一门无刷新技术构建自己的ajax ...
- 解决socket.error: [Errno 98] Address already in use问题
如果python中socket 绑定的地址正在使用,往往会出现错误, 在linux下: 则会显示“ socket.error: [Errno 98] Address already in use” 在 ...
- JPA 报错解决方案 com.microsoft.sqlserver.jdbc.SQLServerException: Cannot insert explicit value for identity column in table 'test_db' when IDENTITY_INSERT is set to OFF.
这种错误插入数据时就是hibernate的自增长字段生成规则应该用native 在字段前加入注解 @GeneratedValue(generator="generator") @G ...
- python之数据分析pandas
做数据分析的同学大部分入门都是从excel开始的,excel也是微软office系列评价最高的一种工具. 但当数据量超过百万行的时候,excel就无能无力了,python第三方包pandas极大的扩展 ...