page.title=Creating a Manager for Multiple Threads trainingnavtop=true @jd:body
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.
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
synchronized
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
Processes and Threads API guide.
Instantiate {@link java.util.concurrent.ThreadPoolExecutor} in its own class. Within this class, do the following:
public class PhotoManager { ... static { ... // Creates a single static instance of PhotoManager sInstance = new PhotoManager(); } ...
synchronized
block:
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() { ... }
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()); ... }
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) { ... } ... } }
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:
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(); }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 active cores, which may be less than the total number of cores.
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>(); ... } ... }
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:
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); }