Home | History | Annotate | Download | only in multiple-threads
      1 page.title=Creating a Manager for Multiple Threads
      2 
      3 trainingnavtop=true
      4 @jd:body
      5 
      6 <div id="tb-wrapper">
      7 <div id="tb">
      8 
      9 <!-- table of contents -->
     10 <h2>This lesson teaches you to</h2>
     11 <ol>
     12   <li><a href="#ClassStructure">Define the Thread Pool Class</a>
     13   <li><a href="#PoolParameters">Determine the Thread Pool Parameters</a></li>
     14   <li><a href="#ThreadPool">Create a Pool of Threads</a></li>
     15 </ol>
     16 
     17 <!-- other docs (NOT javadocs) -->
     18 <h2>You should also read</h2>
     19 <ul>
     20   <li><a href="{@docRoot}guide/components/processes-and-threads.html">Processes and Threads</a></li>
     21 </ul>
     22 
     23 <h2>Try it out</h2>
     24 <div class="download-box">
     25     <a href="{@docRoot}shareables/training/ThreadSample.zip" class="button">Download the sample</a>
     26     <p class="filename">ThreadSample.zip</p>
     27 </div>
     28 
     29 
     30 </div>
     31 </div>
     32 
     33 <p>
     34     The previous lesson showed how to define a task that executes on a
     35     separate thread. If you only want to run the task once, this may be all you need. If you want
     36     to run a task repeatedly on different sets of data, but you only need one execution running at a
     37     time, an {@link android.app.IntentService} suits your needs. To automatically run tasks
     38     as resources become available, or to allow multiple tasks to run at the same time (or both),
     39     you need to provide a managed collection of threads. To do this, use an instance of
     40     {@link java.util.concurrent.ThreadPoolExecutor}, which runs a task from a queue when a thread
     41     in its pool becomes free. To run a task, all you have to do is add it to the queue.
     42 </p>
     43 <p>
     44     A thread pool can run multiple parallel instances of a task, so you should ensure that your
     45     code is thread-safe. Enclose variables that can be accessed by more than one thread in a
     46     <code>synchronized</code> block. This approach will prevent one thread from reading the variable
     47     while another is writing to it. Typically, this situation arises with static variables, but it
     48     also occurs in any object that is only instantiated once. To learn more about this, read the
     49     <a href="{@docRoot}guide/components/processes-and-threads.html">
     50     Processes and Threads</a> API guide.
     51     
     52 </p>
     53 <h2 id="ClassStructure">Define the Thread Pool Class</h2>
     54 <p>
     55     Instantiate {@link java.util.concurrent.ThreadPoolExecutor} in its own class. Within this class,
     56     do the following:
     57 </p>
     58 <dl>
     59     <dt>
     60         Use static variables for thread pools
     61     </dt>
     62     <dd>
     63         You may only want a single instance of a thread pool for your app, in order to have a
     64         single control point for restricted CPU or network resources. If you have different
     65         {@link java.lang.Runnable} types, you may want to have a thread pool for each one, but each
     66         of these can be a single instance. For example, you can add this as part of your
     67         global field declarations:
     68 <pre>
     69 public class PhotoManager {
     70     ...
     71     static  {
     72         ...
     73         // Creates a single static instance of PhotoManager
     74         sInstance = new PhotoManager();
     75     }
     76     ...
     77 </pre>
     78     </dd>
     79     <dt>
     80         Use a private constructor
     81     </dt>
     82     <dd>
     83         Making the constructor private ensures that it is a singleton, which means that you don't
     84         have to enclose accesses to the class in a <code>synchronized</code> block:
     85 <pre>
     86 public class PhotoManager {
     87     ...
     88     /**
     89      * Constructs the work queues and thread pools used to download
     90      * and decode images. Because the constructor is marked private,
     91      * it's unavailable to other classes, even in the same package.
     92      */
     93     private PhotoManager() {
     94     ...
     95     }
     96 </pre>
     97     </dd>
     98     <dt>
     99         Start your tasks by calling methods in the thread pool class.
    100     </dt>
    101     <dd>
    102         Define a method in the thread pool class that adds a task to a thread pool's queue. For
    103         example:
    104 <pre>
    105 public class PhotoManager {
    106     ...
    107     // Called by the PhotoView to get a photo
    108     static public PhotoTask startDownload(
    109         PhotoView imageView,
    110         boolean cacheFlag) {
    111         ...
    112         // Adds a download task to the thread pool for execution
    113         sInstance.
    114                 mDownloadThreadPool.
    115                 execute(downloadTask.getHTTPDownloadRunnable());
    116         ...
    117     }
    118 </pre>
    119     </dd>
    120     <dt>
    121         Instantiate a {@link android.os.Handler} in the constructor and attach it to your app's
    122         UI thread.
    123     </dt>
    124     <dd>
    125         A {@link android.os.Handler} allows your app to safely call the methods of UI objects
    126         such as {@link android.view.View} objects. Most UI objects may only be safely altered from
    127         the UI thread. This approach is described in more detail in the lesson
    128         <a href="communicate-ui.html">Communicate with the UI Thread</a>. For example:
    129 <pre>
    130     private PhotoManager() {
    131     ...
    132         // Defines a Handler object that's attached to the UI thread
    133         mHandler = new Handler(Looper.getMainLooper()) {
    134             /*
    135              * handleMessage() defines the operations to perform when
    136              * the Handler receives a new Message to process.
    137              */
    138             &#64;Override
    139             public void handleMessage(Message inputMessage) {
    140                 ...
    141             }
    142         ...
    143         }
    144     }
    145 </pre>
    146     </dd>
    147 </dl>
    148 <h2 id="PoolParameters">Determine the Thread Pool Parameters</h2>
    149 <p>
    150     Once you have the overall class structure, you can start defining the thread pool. To
    151     instantiate a {@link java.util.concurrent.ThreadPoolExecutor} object, you need the
    152     following values:
    153 </p>
    154 <dl>
    155     <dt>
    156         Initial pool size and maximum pool size
    157     </dt>
    158     <dd>
    159         The initial number of threads to allocate to the pool, and the maximum allowable number.
    160         The number of threads you can have in a thread pool depends primarily on the number of cores
    161         available for your device. This number is available from the system environment:
    162 <pre>
    163 public class PhotoManager {
    164 ...
    165     /*
    166      * Gets the number of available cores
    167      * (not always the same as the maximum number of cores)
    168      */
    169     private static int NUMBER_OF_CORES =
    170             Runtime.getRuntime().availableProcessors();
    171 }
    172 </pre>
    173         This number may not reflect the number of physical cores in the device; some devices have
    174         CPUs that deactivate one or more cores depending on the system load. For these devices,
    175         {@link java.lang.Runtime#availableProcessors availableProcessors()} returns the number of
    176         <i>active</i> cores, which may be less than the total number of cores.
    177     </dd>
    178     <dt>
    179         Keep alive time and time unit
    180     </dt>
    181     <dd>
    182         The duration that a thread will remain idle before it shuts down. The duration is
    183         interpreted by the time unit value, one of the constants defined in
    184         {@link java.util.concurrent.TimeUnit}.
    185     </dd>
    186     <dt>
    187         A queue of tasks
    188     </dt>
    189     <dd>
    190         The incoming queue from which {@link java.util.concurrent.ThreadPoolExecutor} takes
    191         {@link java.lang.Runnable} objects. To start code on a thread, a thread pool manager takes a
    192         {@link java.lang.Runnable} object from a first-in, first-out queue and attaches it to the
    193         thread. You provide this queue object when you create the thread pool, using any queue class
    194         that implements the {@link java.util.concurrent.BlockingQueue} interface. To match the
    195         requirements of your app, you can choose from the available queue implementations; to learn
    196         more about them, see the class overview for {@link java.util.concurrent.ThreadPoolExecutor}.
    197         This example uses the {@link java.util.concurrent.LinkedBlockingQueue} class:
    198 <pre>
    199 public class PhotoManager {
    200     ...
    201     private PhotoManager() {
    202         ...
    203         // A queue of Runnables
    204         private final BlockingQueue&lt;Runnable&gt; mDecodeWorkQueue;
    205         ...
    206         // Instantiates the queue of Runnables as a LinkedBlockingQueue
    207         mDecodeWorkQueue = new LinkedBlockingQueue&lt;Runnable&gt;();
    208         ...
    209     }
    210     ...
    211 }
    212 </pre>
    213     </dd>
    214 </dl>
    215 <h2 id="ThreadPool">Create a Pool of Threads</h2>
    216 <p>
    217     To create a pool of threads, instantiate a thread pool manager by calling
    218     {@link java.util.concurrent.ThreadPoolExecutor#ThreadPoolExecutor ThreadPoolExecutor()}.
    219     This creates and manages a constrained group of threads. Because the initial pool size and
    220     the maximum pool size are the same, {@link java.util.concurrent.ThreadPoolExecutor} creates
    221     all of the thread objects when it is instantiated. For example:
    222 </p>
    223 <pre>
    224     private PhotoManager() {
    225         ...
    226         // Sets the amount of time an idle thread waits before terminating
    227         private static final int KEEP_ALIVE_TIME = 1;
    228         // Sets the Time Unit to seconds
    229         private static final TimeUnit KEEP_ALIVE_TIME_UNIT = TimeUnit.SECONDS;
    230         // Creates a thread pool manager
    231         mDecodeThreadPool = new ThreadPoolExecutor(
    232                 NUMBER_OF_CORES,       // Initial pool size
    233                 NUMBER_OF_CORES,       // Max pool size
    234                 KEEP_ALIVE_TIME,
    235                 KEEP_ALIVE_TIME_UNIT,
    236                 mDecodeWorkQueue);
    237     }
    238 </pre>
    239