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

Menjalankan kode di rangkaian kumpulan thread

Panduan sebelumnya, yang mengajarkan cara Membuat pengelola untuk beberapa thread, menunjukkan cara menentukan class yang mengelola kumpulan thread serta tugas yang akan dijalankan. Tutorial ini menunjukkan cara menjalankan tugas pada kumpulan thread. Untuk melakukannya, tambahkan tugas ke antrean pekerjaan kumpulan. Saat thread tersedia, ThreadPoolExecutor mengambil tugas dari antrean dan menjalankannya di thread.

Tutorial ini juga menunjukkan cara menghentikan tugas yang sedang berjalan. Anda mungkin harus melakukan hal ini saat tugas dimulai, tetapi kemudian mengetahui bahwa pekerjaan tersebut tidak perlu. Daripada membuang waktu pemroses, Anda dapat membatalkan tugas thread yang sedang berjalan. Misalnya, jika Anda mendownload gambar dari jaringan dan menggunakan cache, Anda mungkin ingin menghentikan tugas saat mengetahui bahwa gambar tersebut sudah ada dalam cache. Tergantung cara Anda menulis aplikasi, Anda mungkin tidak dapat mendeteksi hal ini sebelum memulai proses download.

Menjalankan tugas di thread dalam kumpulan thread

Untuk memulai objek tugas pada thread dalam kumpulan thread tertentu, teruskan Runnable ke ThreadPoolExecutor.execute(). Panggilan ini menambahkan tugas ke antrean pekerjaan kumpulan thread. Jika thread tidak ada aktivitas sudah tersedia, pengelola akan mengambil tugas yang telah menunggu paling lama dan menjalankannya pada thread:

Kotlin

    object PhotoManager {

        fun handleState(photoTask: PhotoTask, state: Int) {
            when (state) {
                DOWNLOAD_COMPLETE ->
                    // Decodes the image
                    decodeThreadPool.execute(photoTask.getPhotoDecodeRunnable())
                ...
            }
            ...
        }
        ...
    }
    

Java

    public class PhotoManager {
        public void handleState(PhotoTask photoTask, int state) {
            switch (state) {
                // The task finished downloading the image
                case DOWNLOAD_COMPLETE:
                // Decodes the image
                    decodeThreadPool.execute(
                            photoTask.getPhotoDecodeRunnable());
                ...
            }
            ...
        }
        ...
    }
    

Ketika ThreadPoolExecutor memulai Runnable pada sebuah thread, metode run() objek secara otomatis akan dipanggil.

Memutus kode yang sedang berjalan

Untuk menghentikan tugas, Anda harus memutus thread tugas. Untuk bersiap melakukannya, Anda harus menyimpan tuas ke thread tugas saat membuat tugas. Contoh:

Kotlin

    class PhotoDecodeRunnable : Runnable {

        // Defines the code to run for this task
        override fun run() {
            /*
             * Stores the current Thread in the
             * object that contains PhotoDecodeRunnable
             */
            photoTask.setImageDecodeThread(Thread.currentThread())
            ...
        }
        ...
    }
    

Java

    class PhotoDecodeRunnable implements Runnable {
        // Defines the code to run for this task
        public void run() {
            /*
             * Stores the current Thread in the
             * object that contains PhotoDecodeRunnable
             */
            photoTask.setImageDecodeThread(Thread.currentThread());
            ...
        }
        ...
    }
    

Untuk memutus thread, panggil Thread.interrupt(). Perhatikan bahwa objek Thread dikontrol oleh sistem, yang dapat mengubahnya di luar proses aplikasi Anda. Untuk alasan ini, Anda perlu mengunci akses pada thread sebelum memutusnya, dengan menempatkan akses dalam blok synchronized. Contoh:

Kotlin

    object PhotoManager {
        fun cancelAll() {
            /*
             * Creates and populates an array of Runnables with the Runnables in the queue
             */
            val runnableArray: Array<Runnable> = decodeWorkQueue.toTypedArray()
            /*
             * Iterates over the array of Runnables and interrupts each one's Thread.
             */
            synchronized(this) {
                // Iterates over the array of tasks
                runnableArray.map { (it as? PhotoDecodeRunnable)?.mThread }
                        .forEach { thread ->
                            thread?.interrupt()
                        }
            }
        }
        ...
    }
    

Java

    public class PhotoManager {
        public static void cancelAll() {
            /*
             * Creates an array of Runnables that's the same size as the
             * thread pool work queue
             */
            Runnable[] runnableArray = new Runnable[decodeWorkQueue.size()];
            // Populates the array with the Runnables in the queue
            mDecodeWorkQueue.toArray(runnableArray);
            // Stores the array length in order to iterate over the array
            int len = runnableArray.length;
            /*
             * Iterates over the array of Runnables and interrupts each one's Thread.
             */
            synchronized (sInstance) {
                // Iterates over the array of tasks
                for (int runnableIndex = 0; runnableIndex < len; runnableIndex++) {
                    // Gets the current thread
                    Runnable runnable = runnableArray[runnableIndex];
                    Thread thread = null;
                    if (runnable instanceof PhotoDecodeRunnable) {
                        thread = ((PhotoDecodeRunnable)runnable).mThread;
                    }
                    // if the Thread exists, post an interrupt to it
                    if (null != thread) {
                        thread.interrupt();
                    }
                }
            }
        }
        ...
    }
    

Pada kebanyakan kasus, Thread.interrupt() langsung menghentikan thread. Namun, perintah tersebut hanya menghentikan thread yang sedang menunggu, dan tidak akan memutus tugas intensif jaringan atau CPU. Agar sistem tidak melambat atau terkunci, Anda harus menguji setiap permintaan pemutusan yang tertunda sebelum mencoba operasinya:

Kotlin

    /*
     * Before continuing, checks to see that the Thread hasn't
     * been interrupted
     */
    if (Thread.interrupted()) return
    ...
    // Decodes a byte array into a Bitmap (CPU-intensive)
    BitmapFactory.decodeByteArray(imageBuffer, 0, imageBuffer.size, bitmapOptions)
    ...
    

Java

    /*
     * Before continuing, checks to see that the Thread hasn't
     * been interrupted
     */
    if (Thread.interrupted()) {
        return;
    }
    ...
    // Decodes a byte array into a Bitmap (CPU-intensive)
    BitmapFactory.decodeByteArray(
            imageBuffer, 0, imageBuffer.length, bitmapOptions);
    ...
    

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.