diff options
author | Joe Malin <jmalin@google.com> | 2012-11-26 14:06:35 -0800 |
---|---|---|
committer | Joe Malin <jmalin@google.com> | 2012-12-19 09:47:04 -0800 |
commit | 8dd6275e2871bea1acb20cbdd98ea0451b3d5be0 (patch) | |
tree | 51efc474f81e56f646c2f815e9c919abc2a7a80d /docs/html/training/multiple-threads/create-threadpool.jd | |
parent | ba34f097df278ce1861ebfecdaf634f519ba1f36 (diff) | |
download | frameworks_base-8dd6275e2871bea1acb20cbdd98ea0451b3d5be0.zip frameworks_base-8dd6275e2871bea1acb20cbdd98ea0451b3d5be0.tar.gz frameworks_base-8dd6275e2871bea1acb20cbdd98ea0451b3d5be0.tar.bz2 |
Android Training: Multiple Threads
Change-Id: I58c472aa5ed82f6b4fb50d9bbb4e66841b9e99c3
Diffstat (limited to 'docs/html/training/multiple-threads/create-threadpool.jd')
-rw-r--r-- | docs/html/training/multiple-threads/create-threadpool.jd | 238 |
1 files changed, 238 insertions, 0 deletions
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> |