Android 线程池系列教程(3) 创建线程池
1.This lesson teaches you to
2.You should also read
3. Try it out
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, anIntentService
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.
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.
4.Define the Thread Pool Class
Instantiate ThreadPoolExecutor
in its own class. Within this class, do the following:
- 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
Runnable
types, 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: -
1 public class PhotoManager { 2 ... 3 static { 4 ... 5 // Creates a single static instance of PhotoManager 6 sInstance = new PhotoManager(); 7 } 8 ...
- 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
synchronized
block: -
1 public class PhotoManager { 2 ... 3 /** 4 * Constructs the work queues and thread pools used to download 5 * and decode images. Because the constructor is marked private, 6 * it's unavailable to other classes, even in the same package. 7 */ 8 private PhotoManager() { 9 ... 10 }
- 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:
-
1 public class PhotoManager { 2 ... 3 // Called by the PhotoView to get a photo 4 static public PhotoTask startDownload( 5 PhotoView imageView, 6 boolean cacheFlag) { 7 ... 8 // Adds a download task to the thread pool for execution 9 sInstance. 10 mDownloadThreadPool. 11 execute(downloadTask.getHTTPDownloadRunnable()); 12 ... 13 }
- Instantiate a
Handler
in the constructor and attach it to your app's UI thread. - A
Handler
allows your app to safely call the methods of UI objects such asView
objects. Most UI objects may only be safely altered from the UI thread. This approach is described in more detail in the lesson Communicate with the UI Thread. For example: -
1 private PhotoManager() { 2 ... 3 // Defines a Handler object that's attached to the UI thread 4 mHandler = new Handler(Looper.getMainLooper()) { 5 /* 6 * handleMessage() defines the operations to perform when 7 * the Handler receives a new Message to process. 8 */ 9 @Override 10 public void handleMessage(Message inputMessage) { 11 ... 12 } 13 ... 14 } 15 }
5.Determine the Thread Pool Parameters
Once you have the overall class structure, you can start defining the thread pool. To instantiate aThreadPoolExecutor
object, you need the following values:
- 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:
-
1 public class PhotoManager { 2 ... 3 /* 4 * Gets the number of available cores 5 * (not always the same as the maximum number of cores) 6 */ 7 private static int NUMBER_OF_CORES = 8 Runtime.getRuntime().availableProcessors(); 9 }
- 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. - 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
. - A queue of tasks
- The incoming queue from which
ThreadPoolExecutor
takesRunnable
objects. To start code on a thread, a thread pool manager takes aRunnable
object 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 theBlockingQueue
interface. 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 theLinkedBlockingQueue
class: -
1 public class PhotoManager { 2 ... 3 private PhotoManager() { 4 ... 5 // A queue of Runnables 6 private final BlockingQueue<Runnable> mDecodeWorkQueue; 7 ... 8 // Instantiates the queue of Runnables as a LinkedBlockingQueue 9 mDecodeWorkQueue = new LinkedBlockingQueue<Runnable>(); 10 ... 11 } 12 ... 13 }
6.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, ThreadPoolExecutor
creates all of the thread objects when it is instantiated. For example:
1 private PhotoManager() { 2 ... 3 // Sets the amount of time an idle thread waits before terminating 4 private static final int KEEP_ALIVE_TIME = 1; 5 // Sets the Time Unit to seconds 6 private static final TimeUnit KEEP_ALIVE_TIME_UNIT = TimeUnit.SECONDS; 7 // Creates a thread pool manager 8 mDecodeThreadPool = new ThreadPoolExecutor( 9 NUMBER_OF_CORES, // Initial pool size 10 NUMBER_OF_CORES, // Max pool size 11 KEEP_ALIVE_TIME, 12 KEEP_ALIVE_TIME_UNIT, 13 mDecodeWorkQueue); 14 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?