summaryrefslogtreecommitdiffstats
path: root/docs/html/training/multiple-threads/create-threadpool.jd
blob: 4a4ddb1255f8f20d00ebd41726c02f039c1f412f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
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>