Create a multithreaded manager instance in Android

  • 2020-06-01 11:01:03
  • OfStack

If you're going to do 1 task over and over again, with different data sets (different parameters), but only one at a time (the task is single-threaded), IntentService fits your needs. To automate tasks when resources are available, or to allow multitasking, you need a thread manager to manage your threads. ThreadPoolExecutor, which maintains a queue, fetches tasks from the queue and executes them when its thread pool is free. To run a task, all you have to do is add it to the queue.

Thread pools can run multiple instances of one task in parallel, so you want to keep your code thread-safe. Can be multithreaded access variables need to be synchronized block. For more information, see Processes and Threads (http: / / developer. android. com/guide/components/processes - and - threads. html)

Define the thread pool class

Instance ThreadPoolExecutor in its own class. In the class, do the following:

Use the static variable for the thread pool

You may only need a singleton thread pool in app, in order to enforce 1 control limiting CPU or network resources. If you have different types of Runnable, you might want to have separate thread pools for each type, but these can all be put into a single instance of 1. For example, you can declare it as a global variable:


public class PhotoManager {
    ...
    static  {
        ...
        // Creates a single static instance of PhotoManager
        sInstance = new PhotoManager();
    }
    ...

Use the private constructor

Declaring the constructor as private ensures singletons, which means you don't need to encapsulate class access in synchronized code blocks.


 public class PhotoManager {
        ...
        /**
         * Build for download and decode Picture the work queue and thread pool, because the constructor is marked as private,
         * Not accessible to other classes ( Even the same classes under the package )
         */
        private PhotoManager() {
            ...
        }

Call the method in the thread pool class to start the task

Thread pool class defines a method to add tasks to the thread pool queue, such as:


public class PhotoManager {
    ...
    // for PhotoView Call fetch image
    static public PhotoTask startDownload(
        PhotoView imageView,
        boolean cacheFlag) {
        ...
        // add 1 Four tasks to the thread pool
        sInstance.
                mDownloadThreadPool.
                execute(downloadTask.getHTTPDownloadRunnable());
        ...
    }

Instantiate the Handler of one UI thread.

Handler is used to communicate with UI threads, and most UI controls only allow modifications in UI threads.


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) {
                ...
            }
        ...
        }
    }

Determine the thread pool parameter

Once you have the full class structure, you can start defining the thread pool. To instantiate a thread pool object, you need the following values:
Initial pool size, maximum pool size.
The number of threads in the thread pool depends on the number of CPU cores of the device. This can be obtained from the system environment.


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 cpu cores of the device; For some devices, CPU, which automatically disables parts of the kernel based on system load, availableProcessors() returns the number of active kernels.

Maintain active time and time units

The amount of time a process remains idle before it is shut down. The unit of time is in TimeUnit

Task queue

ThreadPoolExecutor's queue stores Runnable objects. When code is executed in a thread, the thread pool manager pulls an Runnable object from an FIFO queue and attaches it to the thread. The queue implements the BlockingQueue interface, which is provided when the thread pool is created. You can choose one of the existing implementations to suit your needs. See ThreadPoolExecutor. Here is an example of using LinkedBlockingQueue:


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>();
        ...
    }
    ...
}

Creating a thread pool

Call the ThreadPoolExecutor() method to initialize the thread pool. It will create the administrative thread. Since the initial size of the thread pool is the same as the maximum pool size of 1, ThreadPoolExecutor creates all thread objects at initialization time, such as:

    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);
    }


Related articles: