Android官方开发文档Training系列课程中文版:线程执行操作之线程池操作

简介: 原文地址:http://android.xsoftlab.net/training/multiple-threads/run-code.html#StopThread上节课我们学习了如何定义一个类用于管理线程以及任务。

原文地址:http://android.xsoftlab.net/training/multiple-threads/run-code.html#StopThread

上节课我们学习了如何定义一个类用于管理线程以及任务。这节课将会学习如何在线程池中运行任务。要做到这一点,只需要往线程池的工作队列中添加任务即可。当一条线程处于闲置状态时,那么ThreadPoolExecutor会从任务队列中取出一条任务并放入该线程中运行。

这节课还介绍了如何停止一个正在运行中的任务。如果在任务开始后,可能发现这项任务并不是必须的,那么就需要用到任务取消的功能了。这样可以避免浪费处理器的时间。举个例子,如果你正从网络上下载一张图像,如果侦测到这张图像已经在缓存中了,那么这时就需要停止这项网络任务了。

在线程池中的线程内运行任务

为了在指定的线程池中启动一项线程任务,需要将Runnable对象传给ThreadPoolExecutor的execute()方法。这个方法会将任务添加到线程池的工作队列中去。当其中一个线程变为闲置状态时,那么线程池管理器会从队列中取出一个已经等待了很久的任务,然后放到这个线程中运行:

public class PhotoManager {
    public void handleState(PhotoTask photoTask, int state) {
        switch (state) {
            // The task finished downloading the image
            case DOWNLOAD_COMPLETE:
            // Decodes the image
                mDecodeThreadPool.execute(
                        photoTask.getPhotoDecodeRunnable());
            ...
        }
        ...
    }
    ...
}

当ThreadPoolExecutor启动一个Runnable时,它会自动调用Runnable的run()方法。

中断执行中的代码

如果要停止一项任务,那么需要中断该任务所在的线程。为了可以预先做到这一点,那么需要在任务创建时存储该任务所在线程的句柄:

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
         */
        mPhotoTask.setImageDecodeThread(Thread.currentThread());
        ...
    }
    ...
}

我们可以调用Thread.interrupt()方法来中断一个线程。这里要注意Thread对象是由系统控制的,系统会在应用进程的范围之外修改它们。正因为这个原因,在中断线程之前,需要对线程的访问加锁。通常需要将这部分代码放入同步代码块中:

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[mDecodeWorkQueue.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
                Thread thread = runnableArray[taskArrayIndex].mThread;
                // if the Thread exists, post an interrupt to it
                if (null != thread) {
                    thread.interrupt();
                }
            }
        }
    }
    ...
}

在多数情况下,Thread.interrupt()会使线程立刻停止。然而,它只会将那些正在等待的线程停下来,它并不会中止CPU或网络任务。为了避免使系统变慢或卡顿,你应当在开始任意一项操作之前测试是否有中断请求:

/*
 * 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);
...
目录
相关文章
|
3月前
|
Java 调度 开发者
最新Java基础系列课程--Day14-多线程编程(一)
最新Java基础系列课程--Day14-多线程编程
|
6月前
|
Java 调度
线程的yield操作
线程的yield操作的作用是让出目前正在执行的线程放弃当前的执行,让出CUP权限,使得CPU去执行其他的线程。处于让步状态的JVM层面的线程状态仍然是RUNNABLE状态,但是该线程所对应的操作系统层面的线程从状态上来说会从执行状态编程就绪状态。线程yield时,线程放弃和重占CPU的时间是不确定的,可能是刚刚放弃CPU,马上又获得CPU执行权限,重新开始执行。
27 0
|
7月前
|
存储 SQL 安全
Android面试中问的线程相关问题
Android面试中问的线程相关问题
40 0
|
16天前
|
安全 Linux API
Android进程与线程
Android进程与线程
18 0
|
26天前
|
Java Android开发
Android开发系列全套课程
本系列课程面向有java基础,想进入企业从事android开发的计算机专业者。学习搭配实战案例,高效掌握岗位知识。
17 1
|
3月前
|
存储 Java 调度
最新Java基础系列课程--Day14-多线程编程(三)
最新Java基础系列课程--Day14-多线程编程
|
3月前
|
安全 Java
最新Java基础系列课程--Day14-多线程编程(二)
最新Java基础系列课程--Day14-多线程编程
|
3月前
|
存储 算法 Linux
一起聊聊内核中的线程:操作函数、进程状态、task_struct、举个例子、
一起聊聊内核中的线程:操作函数、进程状态、task_struct、举个例子、
62 0
|
4月前
|
监控 安全 Windows
4.3 Windows驱动开发:监控进程与线程对象操作
在内核中,可以使用`ObRegisterCallbacks`这个内核回调函数来实现监控进程和线程对象操作。通过注册一个`OB_CALLBACK_REGISTRATION`回调结构体,可以指定所需的回调函数和回调的监控类型。这个回调结构体包含了回调函数和监控的对象类型,还有一个`Altitude`字段,用于指定回调函数的优先级。优先级越高的回调函数会先被调用,如果某个回调函数返回了一个非NULL值,后续的回调函数就不会被调用。当有进程或线程对象创建、删除、复制或重命名时,内核会调用注册的回调函数。回调函数可以访问被监控对象的信息,如句柄、进程ID等,并可以采取相应的操作,如打印日志、记录信息等。
26 0
4.3 Windows驱动开发:监控进程与线程对象操作
|
9月前
|
Java
【Java】Java中让线程休眠一段时间再进行如何操作?
【Java】Java中让线程休眠一段时间再进行如何操作?
94 0