Minggu, 09 Februari 2014

pemecahan masalah tabrakan sumber daya bersama

Pemecahan Masalah Tabrakan Sumber Daya Bersama

Untuk memecahkan masalah tabrakan pada thread, hampir semua metode serentak melakukan akses serial ke suatu sumber daya yang digunakan bersama. Artinya hanya satu thread yang bisa mengakses suatu sumber daya pada suatu waktu. Biasanya hal ini dilakukan dengan membuat kunci sehingga satu thread saja yang bisa mengakses kunci tersebut. Kunci ini sering disebut mutex atau mutual exclusion.

Mari kita ambil contoh di rumah kita hanya ada satu kamar mandi. Beberapa orang (thread) ingin masuk ke kamar mandi (sumber daya bersama), dan mereka ingin masuk sendirian. Untuk masuk ke dalam kamar mandi, seseorang harus mengetok pintu untuk mengetahui apakah ada orang di dalamnya. Jika tidak ada, maka mereka bisa masuk dan mengunci pintunya. Thread lain yang mau menggunakan kamar mandi "diblok" sehingga tidak bisa masuk, sehingga thread harus menunggu hingga seseorang keluar dari kamar mandi.

Analogi di atas sedikit berbeda jika ketika seseorang keluar dari kamar mandi dan ada beberapa orang yang ingin mengakses kamar mandi secara bersamaan. Karena tidak ada "antrian" maka kita tidak tahu siapa yang harus masuk berikutnya, artinya penjadwal thread bersifat non-deterministik. Yang terjadi adalah, jika banyak orang menunggu di depan kamar mandi, maka siapa yang paling dekat dengan kamar mandi akan masuk terlebih dahulu. Seperti telah diulas sebelumnya, kita bisa memberi tahu penjadwal thread dengan perintah yield dan setPriority() akan tetapi tetap saja masih sangat bergantung kepada JVM dan implementasi pada suatu platform dan tidak bisa ditentukan dengan pasti siapa yang berhak masuk terlebih dahulu.

Java memiliki fitur untuk mencegah terjadinya tabrakan sumber daya, yaitu dengan menggunakan kata kunci synchronized. Ketika suatu thread berusaha untuk mengeksekusi suatu perintah yang diberi kata kunci synchronized, Java akan mengecek apakah sumber daya tersebut tersedia. Jika ya, maka kunci ke sumber daya tersebut akan diambil, kemudian perintah dijalankan, dan setelah selesai melepaskannya kembali. Akan tetapi synchronized tidak selalu berhasil.

Sumber daya bersama bisa berbentuk lokasi memori (dalam bentuk objek), atau bisa juga berupa file, I/O atau bahkan printer. Untuk mengontrol akses ke sumber daya bersama, kita biasanya membungkusnya dalam bentuk objek. Metode lain yang mencoba untuk mengakses sumber daya tersebut bisa diberi kata kunci synchronized. Artinya jika thread sedang mengeksekusi salah satu metode synchronized, thread lain diblok untuk mengeksekusi metode synchronized lain dalam kelas itu hingga thread pertama selesai.
Karena biasanya data dari suatu kelas kita buat private dan akses ke memori hanya bisa dilakukan dengan menggunakan metode, maka kita bisa mencegah tabrakan dengan membuat metode menjadi synchronized. Berikut ini adalah contoh pendeklarasian synchronized.

synchronized void a() { /* perintah Anda di sini */ }
synchronized void b() { /* perintah Anda di sini */ }

Setiap objek memiliki kunci masing-masing yang otomatis dibuat ketka objek tersebut dibuat (kita tidak perlu membuat kode spesial). Ketika kita memanggil metode yang diberi tanda synchronized, objek tersebut dikunci dan tidak boleh ada lagi metode synchronized yang bisa dieksekusi hingga metode sebelumnya selesai dijalankan dan kunci dilepas. Karena hanya ada satu kunci untuk setiap objek, maka kita tidak mungkin menyimpan 2 data pada satu tempat pada saat yang bersamaan.

Satu thread bisa mengunci objek beberapa kali. Ini terjadi jika satu metode memanggil metode lain di kelas yang sama, kemudian metode tersebut memanggil metode lain lagi di kelas yang sama dan seterusnya. JVM akan melacak berapa kali objek tersebut terkunci. Setiap kali suatu metode selesai, kunci akan dilepas. Ketika objek tidak terkunci lagi, maka kuncinya bernilai 0, yang artinya thread lain bisa mulai menggunakan metode pada objek ini.

Ada juga kunci per kelas, yang artinya kunci ini berlaku untuk suatu kelas. Otomatis semua objek yang diciptakan dari kelas yang sama memiliki kunci bersama. Caranya yaitu dengan menggunakan synchronized static metode sehingga suatu objek bisa juga mengunci kelas sehingga objek lain yang menggunakan metode ini tidak bisa jalan apabila sedang digunakan oleh objek lain.

Memperbaiki SelaluGenap
Kita akan ubah sedikit program SelaluGenap di awal bagian ini untuk memberikan kata kunci synchronized pada metode berikut() dan ambilNilai(). Jika kita hanya meletakkan kunci pada salah satu metode, maka metode yang tidak diberi kunci akan tetap bebas untuk dieksekusi mengabaikan ada atau tidaknya kunci. Di sini lah kunci pemrograman serentak, di mana kita harus memberi kunci di setiap akses ke sumber daya bersama.
Metode ini akan berjalan terus menerus, oleh karena itu kita akan gunakan waktuMulai untuk menyimpan waktu ketika thread mulai berjalan, kemudian secara periodik mengecek waktu saat ini. Jika proses sudah berjalan lebih dari 4 detik, kita hentikan proses kemudian mencetak hasilnya.

contoh program :

public class SelaluGenapSynchronized {
    private int i;

    synchronized public void berikut() {
        i++;
        i++;
    }

    synchronized public int ambilNilai() {
        return i;
    }

    public static void main(String[] args) {
        final SelaluGenapSynchronized genap = new SelaluGenapSynchronized();

        new Thread("Kasepna") {
            // mencatat waktu ketika thread dimulai
            private long waktuMulai = System.currentTimeMillis();
            public void run() {
                while (true) {
                    int nilai = genap.ambilNilai();
                    // Jika ganjil, keluar dan cetak nilainya
                    if (nilai % 2 != 0) {
                        System.out.println(nilai);
                        System.exit(0);
                    }
                    // Selesaikan program jika sudah melewati 4 detik
                    if (System.currentTimeMillis() - waktuMulai > 4000) {
                        System.out.println(nilai);
                        System.exit(0);
                    }
                }
            }
        }.start();

        while (true)
            genap.berikut();
    }
}

Bagian Kritis
Kadang-kadang kita hanya ingin mencegah beberapa thread untuk mengakses sebagian kode saja di dalam suatu metode, bukan keseluruhan metode. Bagian kode yang kita ingin lindungi ini disebut bagian kritis (critical section) dan juga bisa dibuat dengan kata kunci synchronized. Akan tetapi, kata kunci ini digunakan dengan menyatakan objek mana yang memiliki kunci yang harus dicek sebelum bagian ini dijalankan.
Berikut ini adalah bentuk umum dari pernyataan synchronized untuk melindung bagian kritis :

synchronized(objekKunci) {
    // Kode di bagian ini hanya bisa diakses
    // Jika objekKunci sedang tidak diakses oleh thread lain
}

Bentuk umum di atas juga disebut blok tersinkron (synchronized block); sebelum blok ini bisa dieksekusi, kunci pada objek objekKunci harus dicek terlebih dahulu. Jika thread lain telah mengunci ojek ini, maka bagian kritis tidak bisa dimasuki hingga thread lain selesai dan melepas kuncinya.




Percobaan :

sebelum membuat class maka buatlah sebuah java project dengan cara klik File --> New --> Java Project , maka akan muncul tampilan seperti gambar dibawah ini :

setelah membuat java project maka kita akan membuat kelas, seperti gambar dibawah ini dengan cara klik File --> New --> Class maka akan muncul tampilan seperti gambar dibawah ini :


Screenshot code diatas :

Kemudian Run program as Java Application diatas dengan klik tombol "play" warna hijau diatas yang saya kasih tunjuk menggunakan pointer mouse saya setelah diklik maka akan muncul tampilan seperti gambar dibawah ini :



setelah klik "OK" maka akan muncul output seperti gambar dibawah ini :



Sumber : http://java.lyracc.com/belajar/java-untuk-pemula/berbagi-sumber-daya

Tidak ada komentar: