| 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}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> |