1page.title=Creating a Manager for Multiple Threads 2 3trainingnavtop=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> 69public 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> 86public 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> 105public 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 @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> 163public 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> 199public class PhotoManager { 200 ... 201 private PhotoManager() { 202 ... 203 // A queue of Runnables 204 private final BlockingQueue<Runnable> mDecodeWorkQueue; 205 ... 206 // Instantiates the queue of Runnables as a LinkedBlockingQueue 207 mDecodeWorkQueue = new LinkedBlockingQueue<Runnable>(); 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