Kamis, 15 Desember 2011

Menghentikan Thread (Java)


Salah satu perubahan pada Java 2 untuk mengurangi kemungkinan terjadinya deadlock adalah dengan dideprekasi (artinya pengembangannya dihentikan, dan user disarankan untuk menghindari penggunaannya) metode stop(),suspend(), dan resume() pada kelas Thread.

Alasan mengapa metode stop() dideprekasi adalah karena metode ini tidak melepas kunci yang sudah dimilikinya, dan jika objek tersebut berada dalam kondisi "cacat" seperti ini, thread lain bisa melihat dan mengubah objek cacat ini. Hasilnya akan muncul masalah yang tersembunyi yang akan sangat sulit dideteksi.

Java menyediakan cara lain untuk menghentikan thread, yaitu dengan mengeset suatu variabel untuk memberi tahu thread tersebut agar menghentikan dirinya sendiri yaitu dengan keluar dari metode run()-nya. Variabel ini akan dicek pada metoderun() yang jika bernilai true, maka metode run() akan berhenti. Berikut ini adalah contohnya :
package com.lyracc.hentikanthread;
 
import java.util.*;
 
class Berhenti extends Thread {
    // Harus bertipe volatile:
    private volatile boolean stop = false;
    private int hitung = 0;
 
    public void run() {
        // Jika stop masih bernilai false teruskan cetak angka
        // Jika stop bernilai true, blok ini tidak lagi dijalankan
        while (!stop && hitung < 10000) {
            System.out.println(hitung++);
        }
        // Jika stop berubah menjadi true
        if (stop)
            System.out.println("Permintaan stop dideteksi");
    }
 
    public void requestStop() {
        stop = true;
    }
}
 
public class HentikanThread {
 
    /**
     * @param args
     */
    public static void main(String[] args) {
 
        final Berhenti threadBaru = new Berhenti();
        threadBaru.start();
        new Timer(true).schedule(new TimerTask() {
            public void run() {
                System.out.println("Permintaan berhenti");
                threadBaru.requestStop();
            }
        }, 500); // run() setelah 500 mili detik
    }
}

Variabel stop harus bertipe volatile sehingga metode run() pasti bisa melihat variabel ini (jika tidak, maka nilainya bisa saja di-cache). Tugas thread ini adalah mencetak 10000 angka, yang akan berhenti ketika hitung >= 10000 atau objek lain meminta berhenti dengan memanggil requestStop(). Perhatikan bahwa requestStop() tidak synchronized karena stop bertipeboolean dan volatile (mengubah boolean menjadi [code]true adalah operasi atomis yang tidak bisa dihentikan di tengah jalan, karena dilakukan dalam 1 clock).

Pada main(), objek Berhenti dimulai. Pada saat yang sama, Timer dimulai untuk memanggil requestStop() setelah setengah detik (500 mili detik). Konstruktor Timer diisi true untuk memastikan bahwa program berhenti saat itu juga.

Menginterupsi Thread yang Diblok

Kadang-kadang, ketika thread dalam keadaan diblok (misalnya ketika sedang menunggu input), thread tersebut tidak bisa membaca variabel seperti kita lakukan di atas. Di sini, kita bisa menggunakan metode interrupt() pada kelas Thread untuk mengeluarkannya dari kondisi diblok. Misalnya,
package com.lyracc.interupsi;
 
import java.util.*;
 
class ThreadDiblok extends Thread {
    public ThreadDiblok() {
        System.out.println("Memulai blokade");
        start();
    }
 
    public void run() {
        try {
            synchronized (this) {
                wait(); // Memblok selamanya
            }
        } catch (InterruptedException e) {
            System.out.println("Diinterupsi");
        }
        System.out.println("Keluar dari run()");
    }
}
 
public class Interupsi {
 
    static ThreadDiblok threadDiBlok = new ThreadDiblok();
 
    /**
     * @param args
     */
    public static void main(String[] args) {
 
        new Timer(true).schedule(new TimerTask() {
            public void run() {
                System.out.println("Bersiap-siap untuk interupsi");
                threadDiBlok.interrupt();
                threadDiBlok = null; // buat null untuk diambil oleh pemulung memori
            }
        }, 2000); // run() setelah 2 detik
    }
}
Panggilan wait() di dalam ThreadDiBlok.run() akan memblok thread selamanya. Ketika Timer selesai, objek akan melakukan interupsi dengan memanggil interrupt(). Kemudian objek threadDiBlok diset ke null sehingga bisa diambil oleh pemulung memori untuk dibersihkan.

Tidak ada komentar:

Posting Komentar