上一篇文章 为多线程创建管理者(manager),介绍了如何定义管理线程池的类。本文主要介绍如何在线程池上运行任务。为了在线程池上运行任务,您应该将任务添加到线程池的工作队列中。当有线程可用时,ThreadPoolExecutor
会从队列中获取一个任务并在线程上运行它。
本文还向您展示了如何停止正在运行的任务。如果任务启动,但随后发现其工作不是必需的,您可以取消运行任务的线程,而不是浪费处理器时间。例如,如果从网络下载图像并使用缓存,则可能需要在检测到缓存中已存在图像时停止任务。
要在特定线程池中的线程上启动任务,请将Runnable
传递给ThreadPoolExecutor.execute()。此调用将任务添加到线程池的工作队列中,当有空闲线程可用时,管理器将获取等待时间最长的任务并在线程上运行它:
-
kotlin
-
object PhotoManager { fun handleState(photoTask: PhotoTask, state: Int) { when (state) { DOWNLOAD_COMPLETE -> // Decodes the image decodeThreadPool.execute(photoTask.getPhotoDecodeRunnable()) ... } ... } ... }
-
java
-
public class PhotoManager { public void handleState(PhotoTask photoTask, int state) { switch (state) { // The task finished downloading the image case DOWNLOAD_COMPLETE: // Decodes the image decodeThreadPool.execute( photoTask.getPhotoDecodeRunnable()); ... } ... } ... }
当ThreadPollExecutor在一个线程中启动Runnable类之后,它会自动调用Runnable类的run()方法。
要停止一个任务,你需要中断执行该任务的线程。要实现此操作,您需要在创建任务时将句柄存储到任务的线程。例如:
- kotlin
class PhotoDecodeRunnable : Runnable {
// Defines the code to run for this task
override fun run() {
/*
* Stores the current Thread in the
* object that contains PhotoDecodeRunnable
*/
photoTask.setImageDecodeThread(Thread.currentThread())
...
}
...
}
- java
class PhotoDecodeRunnable implements Runnable {
// Defines the code to run for this task
public void run() {
/*
* Stores the current Thread in the
* object that contains PhotoDecodeRunnable
*/
photoTask.setImageDecodeThread(Thread.currentThread());
...
}
...
}
要中断线程,请调用Thread.interrupt()。请注意,Thread对象由系统控制,系统可以在应用程序的进程外修改它们。因此,您需要在中断之前获取该线程的锁以获取该线程的访问权限,方法是将访问置于synchronized块中。例如:
- kotlin
object PhotoManager {
fun cancelAll() {
/*
* Creates and populates an array of Runnables with the Runnables in the queue
*/
val runnableArray: Array<Runnable> = decodeWorkQueue.toTypedArray()
/*
* Iterates over the array of Runnables and interrupts each one's Thread.
*/
synchronized(this) {
// Iterates over the array of tasks
runnableArray.map { (it as? PhotoDecodeRunnable)?.mThread }
.forEach { thread ->
thread?.interrupt()
}
}
}
...
}
- java
public class PhotoManager {
public static void cancelAll() {
/*
* Creates an array of Runnables that's the same size as the
* thread pool work queue
*/
Runnable[] runnableArray = new Runnable[decodeWorkQueue.size()];
// Populates the array with the Runnables in the queue
mDecodeWorkQueue.toArray(runnableArray);
// Stores the array length in order to iterate over the array
int len = runnableArray.length;
/*
* Iterates over the array of Runnables and interrupts each one's Thread.
*/
synchronized (sInstance) {
// Iterates over the array of tasks
for (int runnableIndex = 0; runnableIndex < len; runnableIndex++) {
// Gets the current thread
Runnable runnable = runnableArray[runnableIndex];
Thread thread = null;
if (runnable instanceof PhotoDecodeRunnable) {
thread = ((PhotoDecodeRunnable)runnable).mThread;
}
// if the Thread exists, post an interrupt to it
if (null != thread) {
thread.interrupt();
}
}
}
}
...
}
在大多数情况下,Thread.interrupt()会立即停止线程。但是,它只会停止正在等待的线程,并且不会中断CPU或网络密集型任务。为避免减慢或锁定系统,您应该在尝试操作之前测试任何挂起的中断请求:
- kotlin
/*
* Before continuing, checks to see that the Thread hasn't
* been interrupted
*/
if (Thread.interrupted()) return
...
// Decodes a byte array into a Bitmap (CPU-intensive)
BitmapFactory.decodeByteArray(imageBuffer, 0, imageBuffer.size, bitmapOptions)
...
- java
/*
* Before continuing, checks to see that the Thread hasn't
* been interrupted
*/
if (Thread.interrupted()) {
return;
}
...
// Decodes a byte array into a Bitmap (CPU-intensive)
BitmapFactory.decodeByteArray(
imageBuffer, 0, imageBuffer.length, bitmapOptions);
...
更多内容请参阅进程和线程——概述