am d4289c6e: am c84b3603: am 8dd6275e: Android Training: Multiple Threads

* commit 'd4289c6e20c0a42deba796d02b5a9bc60c9a4e7c':
  Android Training: Multiple Threads
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.
+         */
+        &#64;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()) {
+                &#64;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.
+             */
+            &#64;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&lt;Runnable&gt; mDecodeWorkQueue;
+        ...
+        // Instantiates the queue of Runnables as a LinkedBlockingQueue
+        mDecodeWorkQueue = new LinkedBlockingQueue&lt;Runnable&gt;();
+        ...
+    }
+    ...
+}
+</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 {
+    ...
+    &#64;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.
+     */
+    &#64;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 &lt; 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
new file mode 100644
index 0000000..bdc3ccf
--- /dev/null
+++ b/docs/html/training/multiple-threads/threadsample.zip
Binary files differ
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"