Google berkomitmen untuk mendorong terwujudnya keadilan ras bagi komunitas Kulit Hitam. Lihat caranya.

Membuat pengelola untuk beberapa thread

Panduan sebelumnya yang memberi tahu cara Menentukan kode untuk dijalankan pada thread, menunjukkan cara menentukan tugas yang dijalankan pada thread terpisah. Jika hanya ingin menjalankan tugas satu kali, cukup lakukan cara ini. Jika ingin menjalankan tugas berulang kali pada set data yang berbeda, tetapi Anda hanya perlu menjalankan satu eksekusi pada satu waktu, IntentService cocok dengan kebutuhan Anda. Untuk menjalankan tugas secara otomatis saat resource tersedia, atau untuk memungkinkan beberapa tugas berjalan pada waktu yang sama (atau keduanya), Anda perlu menyediakan kumpulan thread yang terkelola. Untuk melakukannya, gunakan instance ThreadPoolExecutor, yang menjalankan tugas dari antrean saat thread dalam kumpulannya menjadi bebas. Untuk menjalankan tugas, Anda perlu menambahkannya ke antrean.

Kumpulan thread dapat menjalankan beberapa instance paralel tugas, jadi pastikan kode Anda aman untuk thread. Masukkan variabel yang dapat diakses oleh lebih dari satu thread di blok synchronized. Pendekatan ini akan mencegah suatu thread membaca variabel saat thread lain menulis untuk variabel tersebut. Biasanya, situasi ini terjadi pada variabel statis, tetapi juga terjadi pada objek apa pun yang hanya dibuat instance-nya satu kali. Untuk mempelajari hal ini lebih lanjut, baca panduan Ringkasan proses dan thread.

Menentukan class kumpulan thread

Buat instance ThreadPoolExecutor di kelasnya sendiri. Dalam class ini, lakukan langkah-langkah berikut:

Gunakan variabel statis untuk kumpulan thread
Anda mungkin hanya menginginkan satu instance dari kumpulan thread untuk aplikasi Anda agar memiliki satu titik kontrol tunggal untuk CPU terbatas atau resource jaringan. Jika memiliki jenis Runnable yang berbeda, Anda mungkin ingin memiliki kumpulan thread untuk setiap jenisnya, tetapi jenis ini dapat menjadi instance tunggal. Misalnya, jenis ini bisa Anda tambahkan sebagai bagian dari deklarasi kolom global (untuk Kotlin, kita dapat membuat sebuah objek):

Kotlin

    // Creates a single static instance of PhotoManager
    object PhotoManager {
        ...
    }
    

Java

    public class PhotoManager {
        ...
        static  {
            ...
            // Creates a single static instance of PhotoManager
            sInstance = new PhotoManager();
        }
        ...
    
Menggunakan konstruktor pribadi
Menjadikan konstruktor sebagai pribadi memastikan bahwa konstruktor tersebut adalah singleton, yang artinya Anda tidak harus menyertakan akses ke class dalam blok synchronized (untuk Kotlin, kita tidak harus memiliki konstruktor pribadi karena konstruktor ini ditetapkan sebagai objek sehingga hanya akan diinisialisasi satu kali):

Kotlin

    object PhotoManager {
        ...
    }
    

Java

    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() {
        ...
        }
    
Mulai tugas Anda dengan memanggil metode di dalam class kumpulan thread.
Tentukan metode di dalam class kumpulan thread yang menambahkan tugas ke antrean kumpulan thread. Misalnya:

Kotlin

    object PhotoManager {
        ...
        fun startDownload(imageView: PhotoView, downloadTask: DownloadTask, cacheFlag: Boolean) =
                decodeThreadPool.execute(downloadTask.getHTTPDownloadRunnable())
        ...
    }
    

Java

    public class PhotoManager {
        ...
        // Called by the PhotoView to get a photo
        static public PhotoTask startDownload(
            PhotoView imageView,
            DownloadTask downloadTask,
            boolean cacheFlag) {
            ...
            // Adds a download task to the thread pool for execution
            sInstance.
                    downloadThreadPool.
                    execute(downloadTask.getHTTPDownloadRunnable());
            ...
        }
    
Buat instance Handler di dalam konstruktor dan lampirkan ke UI thread aplikasi Anda.
Handler memungkinkan aplikasi memanggil metode objek UI secara aman, seperti objek View. Kebanyakan objek UI hanya dapat diubah secara aman dari UI thread. Pendekatan ini dijelaskan lebih detail dalam tutorial Berkomunikasi dengan UI thread. Contoh:

Kotlin

    object PhotoManager {
        ...
        private val handler = object : Handler(Looper.getMainLooper()) {

            /*
             * handleMessage() defines the operations to perform when
             * the Handler receives a new Message to process.
             */
            override fun handleMessage(msg: Message?) {
                ...
            }
            ...
        }
    }
    

Java

        private PhotoManager() {
        ...
            // Defines a Handler object that's attached to the UI thread
            handler = 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) {
                    ...
                }
            ...
            }
        }
    

Menentukan parameter kumpulan thread

Setelah memiliki struktur class secara keseluruhan, Anda dapat mulai menentukan kumpulan thread. Untuk membuat instance objek ThreadPoolExecutor, Anda memerlukan nilai berikut:

Ukuran kumpulan awal dan ukuran kumpulan maksimum
Jumlah awal thread yang akan dialokasikan ke kumpulan, dan jumlah maksimum yang diizinkan. Jumlah thread yang dapat Anda miliki dalam kumpulan thread umumnya bergantung pada jumlah core yang tersedia pada perangkat. Jumlah ini tersedia dari lingkungan sistem:

Kotlin

    object PhotoManager {
        ...
        /*
         * Gets the number of available cores
         * (not always the same as the maximum number of cores)
         */
        private val NUMBER_OF_CORES = Runtime.getRuntime().availableProcessors()
    }
    

Java

    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();
    }
    
Jumlah ini mungkin tidak mencerminkan jumlah core fisik di perangkat; beberapa perangkat memiliki CPU yang menonaktifkan satu atau beberapa core, tergantung muatan sistemnya. Untuk perangkat ini, availableProcessors() menunjukkan jumlah core yang aktif, yang mungkin lebih sedikit dari jumlah total core-nya.
Waktu keep-alive dan satuan waktu
Durasi ketika status thread tetap tidak ada aktivitas sebelum dinonaktifkan. Durasi ditafsirkan oleh nilai satuan waktu, salah satu konstantanya ditentukan dalam TimeUnit.
Antrean tugas
Antrean yang masuk dari ThreadPoolExecutor yang mengambil objek Runnable. Untuk memulai kode pada thread, pengelola kumpulan thread mengambil objek Runnable dari antrean pertama yang masuk, antrean pertama yang keluar, dan melampirkannya ke thread. Berikan objek antrean ini saat Anda membuat kumpulan thread, menggunakan class antrean apa pun yang mengimplementasikan antarmuka BlockingQueue. Agar cocok dengan persyaratan aplikasi, Anda dapat memilih dari implementasi antrean yang tersedia; untuk mempelajarinya lebih lanjut, lihat ringkasan class untuk ThreadPoolExecutor. Contoh ini menggunakan class LinkedBlockingQueue:

Kotlin

    object PhotoManager {
        ...
        // Instantiates the queue of Runnables as a LinkedBlockingQueue
        private val decodeWorkQueue: BlockingQueue<Runnable> = LinkedBlockingQueue<Runnable>()
        ...
    }
    

Java

    public class PhotoManager {
        ...
        private PhotoManager() {
            ...
            // A queue of Runnables
            private final BlockingQueue<Runnable> decodeWorkQueue;
            ...
            // Instantiates the queue of Runnables as a LinkedBlockingQueue
            decodeWorkQueue = new LinkedBlockingQueue<Runnable>();
            ...
        }
        ...
    }
    

Membuat kumpulan thread

Untuk membuat kumpulan thread, buat instance pengelola kumpulan thread dengan memanggil ThreadPoolExecutor(). Instance ini membuat dan mengelola grup thread yang terbatas. Karena ukuran kumpulan awal dan ukuran kumpulan maksimum adalah sama, ThreadPoolExecutor akan membuat semua objek thread saat instance-nya dibuat. Contoh:

Kotlin

    object PhotoManager {
        ...
        // Sets the amount of time an idle thread waits before terminating
        private const val KEEP_ALIVE_TIME = 1L
        // Sets the Time Unit to seconds
        private val KEEP_ALIVE_TIME_UNIT = TimeUnit.SECONDS
        // Creates a thread pool manager
        private val decodeThreadPool: ThreadPoolExecutor = ThreadPoolExecutor(
                NUMBER_OF_CORES,       // Initial pool size
                NUMBER_OF_CORES,       // Max pool size
                KEEP_ALIVE_TIME,
                KEEP_ALIVE_TIME_UNIT,
                decodeWorkQueue
        )
    

Java

        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
            decodeThreadPool = new ThreadPoolExecutor(
                    NUMBER_OF_CORES,       // Initial pool size
                    NUMBER_OF_CORES,       // Max pool size
                    KEEP_ALIVE_TIME,
                    KEEP_ALIVE_TIME_UNIT,
                    decodeWorkQueue);
        }
    

Atau, jika tidak ingin mengelola detail pengukuran kumpulan thread, Anda dapat menggunakan metode pabrik Eksekutor untuk membuat eksekutor thread tunggal atau eksekutor pencuri pekerjaan lebih mudah.

Informasi selengkapnya

Untuk mempelajari operasi multi thread di Android lebih lanjut, lihat panduan Ringkasan proses dan thread.

Contoh aplikasi

Untuk mencoba konsep dalam panduan ini, download ThreadSample.