8dd6275e28
Change-Id: I58c472aa5ed82f6b4fb50d9bbb4e66841b9e99c3
149 lines
5.3 KiB
Plaintext
149 lines
5.3 KiB
Plaintext
page.title=Running Code on a Thread Pool Thread
|
|
|
|
trainingnavtop=true
|
|
@jd:body
|
|
|
|
<div id="tb-wrapper">
|
|
<div id="tb">
|
|
|
|
<!-- table of contents -->
|
|
<h2>This lesson teaches you to</h2>
|
|
<ol>
|
|
<li><a href="#RunRunnable">Run a Runnable on a Thread in the Thread Pool</a></li>
|
|
<li><a href="#StopThread">Interrupt Running Code</a></li>
|
|
</ol>
|
|
|
|
<h2>You should also read</h2>
|
|
<ul>
|
|
<li><a href="{@docRoot}guide/components/processes-and-threads.html">Processes and Threads</a></li>
|
|
</ul>
|
|
|
|
|
|
<h2>Try it out</h2>
|
|
<div class="download-box">
|
|
<a href="{@docRoot}shareables/training/ThreadSample.zip" class="button">Download the sample</a>
|
|
<p class="filename">ThreadSample.zip</p>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
<p>
|
|
The previous lesson showed you how to define a class that manages thread pools and the tasks
|
|
that run on them. This lesson shows you how to run a task on a thread pool. To do this,
|
|
you add the task to the pool's work queue. When a thread becomes available, the
|
|
{@link java.util.concurrent.ThreadPoolExecutor} takes a task from the queue and runs it on the
|
|
thread.
|
|
</p>
|
|
<p>
|
|
This lesson also shows you how to stop a task that's running. You might want to do this if a
|
|
task starts, but then discovers that its work isn't necessary. Rather than wasting processor
|
|
time, you can cancel the thread the task is running on. For example, if you are downloading
|
|
images from the network and using a cache, you probably want to stop a task if it detects that
|
|
an image is already present in the cache. Depending on how you write your app, you may not be
|
|
able to detect this before you start the download.
|
|
</p>
|
|
<h2 id="RunRunnable">Run a Task on a Thread in the Thread Pool</h2>
|
|
<p>
|
|
To start a task object on a thread in a particular thread pool, pass the
|
|
{@link java.lang.Runnable} to {@link java.util.concurrent.ThreadPoolExecutor#execute
|
|
ThreadPoolExecutor.execute()}. This call adds the task to the thread pool's work queue. When an
|
|
idle thread becomes available, the manager takes the task that has been waiting the longest and
|
|
runs it on the thread:
|
|
</p>
|
|
<pre>
|
|
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());
|
|
...
|
|
}
|
|
...
|
|
}
|
|
...
|
|
}
|
|
</pre>
|
|
<p>
|
|
When {@link java.util.concurrent.ThreadPoolExecutor} starts a {@link java.lang.Runnable} on a
|
|
thread, it automatically calls the object's {@link java.lang.Runnable#run run()} method.
|
|
</p>
|
|
<h2 id="StopThread">Interrupt Running Code</h2>
|
|
<p>
|
|
To stop a task, you need to interrupt the task's thread. To prepare to do this, you need to
|
|
store a handle to the task's thread when you create the task. For example:
|
|
</p>
|
|
<pre>
|
|
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());
|
|
...
|
|
}
|
|
...
|
|
}
|
|
</pre>
|
|
<p>
|
|
To interrupt a thread, call {@link java.lang.Thread#interrupt Thread.interrupt()}. Notice that
|
|
{@link java.lang.Thread} objects are controlled by the system, which can modify them outside of
|
|
your app's process. For this reason, you need to lock access on a thread before you
|
|
interrupt it, by placing the access in a <code>synchronized</code> block. For example:
|
|
</p>
|
|
<pre>
|
|
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();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
...
|
|
}
|
|
</pre>
|
|
<p>
|
|
In most cases, {@link java.lang.Thread#interrupt Thread.interrupt()} stops the thread
|
|
immediately. However, it only stops threads that are waiting, and will not interrupt CPU or
|
|
network-intensive tasks. To avoid slowing down or locking up the system, you should test for
|
|
any pending interrupt requests before attempting an operation :
|
|
</p>
|
|
<pre>
|
|
/*
|
|
* 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);
|
|
...
|
|
</pre>
|