diff options
author | Joe Malin <jmalin@google.com> | 2012-12-19 10:35:32 -0800 |
---|---|---|
committer | Android Git Automerger <android-git-automerger@android.com> | 2012-12-19 10:35:32 -0800 |
commit | 4c59230a2fe0ec750b31a0908fbee5c5613b87c0 (patch) | |
tree | 12ea46bf52e85ac59ec8de2123e322b4bd62aa4e /docs | |
parent | 34bdf0abfeaa81b6fe2e8cc95e0ba94893b3e8e8 (diff) | |
parent | d4289c6e20c0a42deba796d02b5a9bc60c9a4e7c (diff) | |
download | frameworks_base-4c59230a2fe0ec750b31a0908fbee5c5613b87c0.zip frameworks_base-4c59230a2fe0ec750b31a0908fbee5c5613b87c0.tar.gz frameworks_base-4c59230a2fe0ec750b31a0908fbee5c5613b87c0.tar.bz2 |
am d4289c6e: am c84b3603: am 8dd6275e: Android Training: Multiple Threads
* commit 'd4289c6e20c0a42deba796d02b5a9bc60c9a4e7c':
Android Training: Multiple Threads
Diffstat (limited to 'docs')
-rw-r--r-- | docs/html/training/multiple-threads/communicate-ui.jd | 263 | ||||
-rw-r--r-- | docs/html/training/multiple-threads/create-threadpool.jd | 238 | ||||
-rw-r--r-- | docs/html/training/multiple-threads/define-runnable.jd | 110 | ||||
-rw-r--r-- | docs/html/training/multiple-threads/index.jd | 83 | ||||
-rw-r--r-- | docs/html/training/multiple-threads/run-code.jd | 148 | ||||
-rw-r--r-- | docs/html/training/multiple-threads/threadsample.zip | bin | 0 -> 75204 bytes | |||
-rw-r--r-- | docs/html/training/training_toc.cs | 27 |
7 files changed, 869 insertions, 0 deletions
diff --git a/docs/html/training/multiple-threads/communicate-ui.jd b/docs/html/training/multiple-threads/communicate-ui.jd new file mode 100644 index 0000000..d9977d3 --- /dev/null +++ b/docs/html/training/multiple-threads/communicate-ui.jd @@ -0,0 +1,263 @@ +page.title=Communicating with the UI 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="#Handler">Define a Handler on the UI Thread</a></li> + <li><a href="#MoveValues">Move Data from a Task to the UI Thread</a> +</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> + In the previous lesson you learned how to start a task on a thread managed by + {@link java.util.concurrent.ThreadPoolExecutor}. This final lesson shows you how to send data + from the task to objects running on the user interface (UI) thread. This feature allows your + tasks to do background work and then move the results to UI elements such as bitmaps. +</p> +<p> + Every app has its own special thread that runs UI objects such as {@link android.view.View} + objects; this thread is called the UI thread. Only objects running on the UI thread have access + to other objects on that thread. Because tasks that you run on a thread from a thread pool + <em>aren't</em> running on your UI thread, they don't have access to UI objects. To move data + from a background thread to the UI thread, use a {@link android.os.Handler} that's + running on the UI thread. +</p> +<h2 id="Handler">Define a Handler on the UI Thread</h2> +<p> + {@link android.os.Handler} is part of the Android system's framework for managing threads. A + {@link android.os.Handler} object receives messages and runs code to handle the messages. + Normally, you create a {@link android.os.Handler} for a new thread, but you can + also create a {@link android.os.Handler} that's connected to an existing thread. + When you connect a {@link android.os.Handler} to your UI thread, the code that handles messages + runs on the UI thread. +</p> +<p> + Instantiate the {@link android.os.Handler} object in the constructor for the class that + creates your thread pools, and store the object in a global variable. Connect it to the UI + thread by instantiating it with the {@link android.os.Handler#Handler(Looper) Handler(Looper)} + constructor. This constructor uses a {@link android.os.Looper} object, which is another part of + the Android system's thread management framework. When you instantiate a + {@link android.os.Handler} based on a particular {@link android.os.Looper} instance, the + {@link android.os.Handler} runs on the same thread as the {@link android.os.Looper}. + For example: +</p> +<pre> +private PhotoManager() { +... + // Defines a Handler object that's attached to the UI thread + mHandler = new Handler(Looper.getMainLooper()) { + ... +</pre> +<p> + Inside the {@link android.os.Handler}, override the {@link android.os.Handler#handleMessage + handleMessage()} method. The Android system invokes this method when it receives a new message + for a thread it's managing; all of the {@link android.os.Handler} objects for a particular + thread receive the same message. For example: +</p> +<pre> + /* + * handleMessage() defines the operations to perform when + * the Handler receives a new Message to process. + */ + @Override + public void handleMessage(Message inputMessage) { + // Gets the image task from the incoming Message object. + PhotoTask photoTask = (PhotoTask) inputMessage.obj; + ... + } + ... + } +} +The next section shows how to tell the {@link android.os.Handler} to move data. +</pre> +<h2 id="MoveValues">Move Data from a Task to the UI Thread</h2> +<p> + To move data from a task object running on a background thread to an object on the UI thread, + start by storing references to the data and the UI object in the task object. Next, pass the + task object and a status code to the object that instantiated the {@link android.os.Handler}. + In this object, send a {@link android.os.Message} containing the status and the task object to + the {@link android.os.Handler}. Because {@link android.os.Handler} is running on the UI thread, + it can move the data to the UI object. + +<h3>Store data in the task object</h3> +<p> + For example, here's a {@link java.lang.Runnable}, running on a background thread, that decodes a + {@link android.graphics.Bitmap} and stores it in its parent object <code>PhotoTask</code>. + The {@link java.lang.Runnable} also stores the status code <code>DECODE_STATE_COMPLETED</code>. +</p> +<pre> +// A class that decodes photo files into Bitmaps +class PhotoDecodeRunnable implements Runnable { + ... + PhotoDecodeRunnable(PhotoTask downloadTask) { + mPhotoTask = downloadTask; + } + ... + // Gets the downloaded byte array + byte[] imageBuffer = mPhotoTask.getByteBuffer(); + ... + // Runs the code for this task + public void run() { + ... + // Tries to decode the image buffer + returnBitmap = BitmapFactory.decodeByteArray( + imageBuffer, + 0, + imageBuffer.length, + bitmapOptions + ); + ... + // Sets the ImageView Bitmap + mPhotoTask.setImage(returnBitmap); + // Reports a status of "completed" + mPhotoTask.handleDecodeState(DECODE_STATE_COMPLETED); + ... + } + ... +} +... +</pre> +<p> + <code>PhotoTask</code> also contains a handle to the {@link android.widget.ImageView} that + displays the {@link android.graphics.Bitmap}. Even though references to + the {@link android.graphics.Bitmap} and {@link android.widget.ImageView} are in the same object, + you can't assign the {@link android.graphics.Bitmap} to the {@link android.widget.ImageView}, + because you're not currently running on the UI thread. +</p> +<p> + Instead, the next step is to send this status to the <code>PhotoTask</code> object. +</p> +<h3>Send status up the object hierarchy</h3> +<p> + <code>PhotoTask</code> is the next higher object in the hierarchy. It maintains references to + the decoded data and the {@link android.view.View} object that will show the data. It receives + a status code from <code>PhotoDecodeRunnable</code> and passes it along to the object that + maintains thread pools and instantiates {@link android.os.Handler}: +</p> +<pre> +public class PhotoTask { + ... + // Gets a handle to the object that creates the thread pools + sPhotoManager = PhotoManager.getInstance(); + ... + public void handleDecodeState(int state) { + int outState; + // Converts the decode state to the overall state. + switch(state) { + case PhotoDecodeRunnable.DECODE_STATE_COMPLETED: + outState = PhotoManager.TASK_COMPLETE; + break; + ... + } + ... + // Calls the generalized state method + handleState(outState); + } + ... + // Passes the state to PhotoManager + void handleState(int state) { + /* + * Passes a handle to this task and the + * current state to the class that created + * the thread pools + */ + sPhotoManager.handleState(this, state); + } + ... +} +</pre> +<h3>Move data to the UI</h3> +<p> + From the <code>PhotoTask</code> object, the <code>PhotoManager</code> object receives a status + code and a handle to the <code>PhotoTask</code> object. Because the status is + <code>TASK_COMPLETE</code>, creates a {@link android.os.Message} containing the state and task + object and sends it to the {@link android.os.Handler}: +</p> +<pre> +public class PhotoManager { + ... + // Handle status messages from tasks + public void handleState(PhotoTask photoTask, int state) { + switch (state) { + ... + // The task finished downloading and decoding the image + case TASK_COMPLETE: + /* + * Creates a message for the Handler + * with the state and the task object + */ + Message completeMessage = + mHandler.obtainMessage(state, photoTask); + completeMessage.sendToTarget(); + break; + ... + } + ... + } +</pre> +<p> + Finally, {@link android.os.Handler#handleMessage Handler.handleMessage()} checks the status + code for each incoming {@link android.os.Message}. If the status code is + <code>TASK_COMPLETE</code>, then the task is finished, and the <code>PhotoTask</code> object + in the {@link android.os.Message} contains both a {@link android.graphics.Bitmap} and an + {@link android.widget.ImageView}. Because + {@link android.os.Handler#handleMessage Handler.handleMessage()} is + running on the UI thread, it can safely move the {@link android.graphics.Bitmap} to the + {@link android.widget.ImageView}: +</p> +<pre> + private PhotoManager() { + ... + mHandler = new Handler(Looper.getMainLooper()) { + @Override + public void handleMessage(Message inputMessage) { + // Gets the task from the incoming Message object. + PhotoTask photoTask = (PhotoTask) inputMessage.obj; + // Gets the ImageView for this task + PhotoView localView = photoTask.getPhotoView(); + ... + switch (inputMessage.what) { + ... + // The decoding is done + case TASK_COMPLETE: + /* + * Moves the Bitmap from the task + * to the View + */ + localView.setImageBitmap(photoTask.getImage()); + break; + ... + default: + /* + * Pass along other messages from the UI + */ + super.handleMessage(inputMessage); + } + ... + } + ... + } + ... + } +... +} +</pre> diff --git a/docs/html/training/multiple-threads/create-threadpool.jd b/docs/html/training/multiple-threads/create-threadpool.jd new file mode 100644 index 0000000..4a4ddb1 --- /dev/null +++ b/docs/html/training/multiple-threads/create-threadpool.jd @@ -0,0 +1,238 @@ +page.title=Creating a Manager for Multiple Threads + +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="#ClassStructure">Define the Thread Pool Class</a> + <li><a href="#PoolParameters">Determine the Thread Pool Parameters</a></li> + <li><a href="#ThreadPool">Create a Pool of Threads</a></li> +</ol> + +<!-- other docs (NOT javadocs) --> +<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 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 {@link android.app.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 + {@link java.util.concurrent.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. +</p> +<p> + 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 a + <code>synchronized</code> 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 + <a href="{@docRoot}http://developer.android.com/guide/components/processes-and-threads.html"> + Processes and Threads</a> API guide. + +</p> +<h2 id="ClassStructure">Define the Thread Pool Class</h2> +<p> + Instantiate {@link java.util.concurrent.ThreadPoolExecutor} in its own class. Within this class, + do the following: +</p> +<dl> + <dt> + Use static variables for thread pools + </dt> + <dd> + 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 + {@link java.lang.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: +<pre> +public class PhotoManager { + ... + static { + ... + // Creates a single static instance of PhotoManager + sInstance = new PhotoManager(); + } + ... +</pre> + </dd> + <dt> + Use a private constructor + </dt> + <dd> + 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 <code>synchronized</code> block: +<pre> +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() { + ... + } +</pre> + </dd> + <dt> + Start your tasks by calling methods in the thread pool class. + </dt> + <dd> + Define a method in the thread pool class that adds a task to a thread pool's queue. For + example: +<pre> +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()); + ... + } +</pre> + </dd> + <dt> + Instantiate a {@link android.os.Handler} in the constructor and attach it to your app's + UI thread. + </dt> + <dd> + A {@link android.os.Handler} allows your app to safely call the methods of UI objects + such as {@link android.view.View} objects. Most UI objects may only be safely altered from + the UI thread. This approach is described in more detail in the lesson + <a href="communicate-ui.html">Communicate with the UI Thread</a>. For example: +<pre> + 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) { + ... + } + ... + } + } +</pre> + </dd> +</dl> +<h2 id="PoolParameters">Determine the Thread Pool Parameters</h2> +<p> + Once you have the overall class structure, you can start defining the thread pool. To + instantiate a {@link java.util.concurrent.ThreadPoolExecutor} object, you need the + following values: +</p> +<dl> + <dt> + Initial pool size and maximum pool size + </dt> + <dd> + 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: +<pre> +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(); +} +</pre> + 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, + {@link java.lang.Runtime#availableProcessors availableProcessors()} returns the number of + <i>active</i> cores, which may be less than the total number of cores. + </dd> + <dt> + Keep alive time and time unit + </dt> + <dd> + 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 + {@link java.util.concurrent.TimeUnit}. + </dd> + <dt> + A queue of tasks + </dt> + <dd> + The incoming queue from which {@link java.util.concurrent.ThreadPoolExecutor} takes + {@link java.lang.Runnable} objects. To start code on a thread, a thread pool manager takes a + {@link java.lang.Runnable} 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 the {@link java.util.concurrent.BlockingQueue} 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 for {@link java.util.concurrent.ThreadPoolExecutor}. + This example uses the {@link java.util.concurrent.LinkedBlockingQueue} class: +<pre> +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>(); + ... + } + ... +} +</pre> + </dd> +</dl> +<h2 id="ThreadPool">Create a Pool of Threads</h2> +<p> + To create a pool of threads, instantiate a thread pool manager by calling + {@link java.util.concurrent.ThreadPoolExecutor#ThreadPoolExecutor ThreadPoolExecutor()}. + This creates and manages a constrained group of threads. Because the initial pool size and + the maximum pool size are the same, {@link java.util.concurrent.ThreadPoolExecutor} creates + all of the thread objects when it is instantiated. For example: +</p> +<pre> + 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); + } +</pre> diff --git a/docs/html/training/multiple-threads/define-runnable.jd b/docs/html/training/multiple-threads/define-runnable.jd new file mode 100644 index 0000000..17640a9 --- /dev/null +++ b/docs/html/training/multiple-threads/define-runnable.jd @@ -0,0 +1,110 @@ +page.title=Specifying the Code to Run on a 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="#ExtendClass">Define a Class that Implements Runnable</a></li> + <li><a href="#RunMethod">Implement the run() Method</a> +</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> +</div> + +<p> + This lesson shows you how to implement a {@link java.lang.Runnable} class, which runs the code + in its {@link java.lang.Runnable#run Runnable.run()} method on a separate thread. You can also + pass a {@link java.lang.Runnable} to another object that can then attach it to a thread and + run it. One or more {@link java.lang.Runnable} objects that perform a particular operation are + sometimes called a <i>task</i>. +</p> +<p> + {@link java.lang.Thread} and {@link java.lang.Runnable} are basic classes that, on their own, + have only limited power. Instead, they're the basis of powerful Android classes such as + {@link android.os.HandlerThread}, {@link android.os.AsyncTask}, and + {@link android.app.IntentService}. {@link java.lang.Thread} and {@link java.lang.Runnable} are + also the basis of the class {@link java.util.concurrent.ThreadPoolExecutor}. This class + automatically manages threads and task queues, and can even run multiple threads in parallel. +</p> +<h2 id="ExtendClass">Define a Class that Implements Runnable</h2> +<p> + Implementing a class that implements {@link java.lang.Runnable} is straightforward. For example: +</p> +<pre> +public class PhotoDecodeRunnable implements Runnable { + ... + @Override + public void run() { + /* + * Code you want to run on the thread goes here + */ + ... + } + ... +} +</pre> +<h2 id="RunMethod">Implement the run() Method</h2> +<p> + In the class, the {@link java.lang.Runnable#run Runnable.run()} method contains the + code that's executed. Usually, anything is allowable in a {@link java.lang.Runnable}. Remember, + though, that the {@link java.lang.Runnable} won't be running on the UI thread, so it can't + directly modify UI objects such as {@link android.view.View} objects. To communicate with + the UI thread, you have to use the techniques described in the lesson + <a href="communicate-ui.html">Communicate with the UI Thread</a>. +</p> +<p> + At the beginning of the {@link java.lang.Runnable#run run()} method, set the thread to use + background priority by calling + {@link android.os.Process#setThreadPriority Process.setThreadPriority()} with + {@link android.os.Process#THREAD_PRIORITY_BACKGROUND}. This approach reduces + resource competition between the {@link java.lang.Runnable} object's thread and the UI + thread. +</p> +<p> + You should also store a reference to the {@link java.lang.Runnable} object's + {@link java.lang.Thread} in the {@link java.lang.Runnable} itself, by calling + {@link java.lang.Thread#currentThread() Thread.currentThread()}. +</p> +<p> + The following snippet shows how to set up the {@link java.lang.Runnable#run run()} method: +</p> +<pre> +class PhotoDecodeRunnable implements Runnable { +... + /* + * Defines the code to run for this task. + */ + @Override + public void run() { + // Moves the current Thread into the background + android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND); + ... + /* + * Stores the current Thread in the the PhotoTask instance, + * so that the instance + * can interrupt the Thread. + */ + mPhotoTask.setImageDecodeThread(Thread.currentThread()); + ... + } +... +} +</pre> diff --git a/docs/html/training/multiple-threads/index.jd b/docs/html/training/multiple-threads/index.jd new file mode 100644 index 0000000..3ea57c5 --- /dev/null +++ b/docs/html/training/multiple-threads/index.jd @@ -0,0 +1,83 @@ +page.title=Sending Operations to Multiple Threads + +trainingnavtop=true +startpage=true + + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + +<!-- Required platform, tools, add-ons, devices, knowledge, etc. --> +<h2>Dependencies and prerequisites</h2> +<ul> + <li>Android 3.0 (API Level 11) or higher</li> + <li> + <a href="{@docRoot}training/load-data-background/index.html"> + Loading Data in the Background</a> training class + </li> + <li> + <a href="{@docRoot}training/run-background-service/index.html"> + Running in a Background Service</a> training class + </li> +</ul> + +<!-- related docs (NOT javadocs) --> +<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 speed and efficiency of a long-running, data-intensive operation often improves when you + split it into smaller operations running on multiple threads. On a device that has a CPU with + multiple processors (cores), the system can run the threads in parallel, rather than making each + sub-operation wait for a chance to run. For example, decoding multiple image files in order to + display them on a thumbnail screen runs substantially faster when you do each decode on a + separate thread. +</p> +<p> + This class shows you how to set up and use multiple threads in an Android app, using a + thread pool object. You'll also learn how to define code to run on a thread and how to + communicate between one of these threads and the UI thread. +</p> +<h2>Lessons</h2> +<dl> + <dt> + <b><a href="define-runnable.html">Specifying the Code to Run on a Thread</a></b> + </dt> + <dd> + Learn how to write code to run on a separate {@link java.lang.Thread}, by + defining a class that implements the {@link java.lang.Runnable} interface. + </dd> + <dt> + <b><a href="create-threadpool.html">Creating a Manager for Multiple Threads</a></b> + </dt> + <dd> + Learn how to create an object that manages a pool of {@link java.lang.Thread} objects and + a queue of {@link java.lang.Runnable} objects. This object is called a + {@link java.util.concurrent.ThreadPoolExecutor}. + </dd> + <dt> + <b><a href="run-code.html">Running Code on a Thread Pool Thread</a></b> + </dt> + <dd> + Learn how to run a {@link java.lang.Runnable} on a thread from the thread pool. + </dd> + <dt> + <b><a href="communicate-ui.html">Communicating with the UI Thread</a></b> + </dt> + <dd> + Learn how to communicate from a thread in the thread pool to the UI thread. + </dd> +</dl> + diff --git a/docs/html/training/multiple-threads/run-code.jd b/docs/html/training/multiple-threads/run-code.jd new file mode 100644 index 0000000..a828828 --- /dev/null +++ b/docs/html/training/multiple-threads/run-code.jd @@ -0,0 +1,148 @@ +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> diff --git a/docs/html/training/multiple-threads/threadsample.zip b/docs/html/training/multiple-threads/threadsample.zip Binary files differnew file mode 100644 index 0000000..bdc3ccf --- /dev/null +++ b/docs/html/training/multiple-threads/threadsample.zip diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs index c4e0f84..78b0dce 100644 --- a/docs/html/training/training_toc.cs +++ b/docs/html/training/training_toc.cs @@ -925,6 +925,33 @@ </li> </ul> </li> + <li class="nav-section"> + <div class="nav-section-header"> + <a href="<?cs var:toroot ?>training/multiple-threads/index.html" + description= + "How to improve the performance and scalability of long-running operations by + dispatching work to multiple threads."> + Sending Operations to Multiple Threads</a> + </div> + <ul> + <li><a href="<?cs var:toroot ?>training/multiple-threads/define-runnable.html"> + Specifying the Code to Run on a Thread + </a> + </li> + <li><a href="<?cs var:toroot ?>training/multiple-threads/create-threadpool.html"> + Creating a Manager for Multiple Threads + </a> + </li> + <li><a href="<?cs var:toroot ?>training/multiple-threads/run-code.html"> + Running Code on a Thread Pool Thread + </a> + </li> + <li><a href="<?cs var:toroot ?>training/multiple-threads/communicate-ui.html"> + Communicating with the UI Thread + </a> + </li> + </ul> + </li> <li> <a href="<?cs var:toroot ?>training/articles/perf-anr.html" |