PEMROGRAMAN BERORIENTASI OBJEK
“ Sinkronisasi ”
Oleh : Farhat, ST, MMSI, MSc
SINKRONISASI
Sinkronisasi adalah suatu proses pengendalian akses dari sumber daya terbagi pakai (shared resource) oleh banyak thread sedemikian sehingga hanya satu thread yang dapat mengakses sumber daya tertentu pada satu waktu.
Dalam aplikasi multithreaded yang tidak tersinkronisasi, sangat mungkin terjadi adanya satu thread memodifikasi suatu obyek yang dipakai bersama pada saat thread lain sedangkan dalam proses menggunakan atau mengupdate nilai obyek tersebut. Sinkronisasi mencegah jenis kerusakan data demikian, jika tidak disinkronkan maka dapat mengakibatkan pembacaan yang buruk dan error yang signifikan. Secara umum bagian kritis (critical sections) dari kode biasanya ditandai dengan kata kunci synchronized.
Jadi sinkronisasi itu ialah suatu proses pengendalian untuk salah satu thread dari banyak thread untuk dapat mengakses sumber daya tertentu pada satu waktu.
Sinkronisasi merupakan mekanisme untuk mengontrol eksekusi dari thread-thread berbeda sehingga ketika banyak thread mengakses variabel “shared”, dapat dipastikan eksekusinya benar. Java punya keyword synchronized – dapat digunakan untuk memperkenalkan suatu segmen kode atau metode yang akan dapat diakses hanya oleh suatu thread tunggal pada satu waktu.
Sebelum memasuki wilayah sinkronisasi, suatu thread akan memperoleh semaphore yang berasosiasi dengan wilayah tersebut – jika telah diambil oleh thread lain, maka thread tersebut mem-blokir (menunggu) sampai semaphore dilepas.
Dalam Java, obyek dengan satu atau lebih metode synchronized disebut sebagai monitor. Ketika thread memanggil metode synchronized, hanya satu thread yang dibolehkan pada satu waktu, lainnya menunggu dalam antrian (queue). Dalam aplikasi jenis producer- consumer, thread consumer mungkin mendapatkan tidak ada cukup elemen untuk dikonsumsi. Tanggung jawab monitor untuk memastikan bahwa thread-thread yang menunggu producer diberitahu segera setelah elemen-elemen diproduksi.
Suatu lock (kunci) digunakan untuk mengsinkronkan akses ke sumber daya terbagi-pakai. Suatu lock dapat diasosiasikan dengan suatu sumber daya terbagi-pakai. Thread memperoleh akses ke sumber daya terbagi-pakai dengan terlebih dahulu mendapatkan lock yang terasosiasi dengan obyek atau block dari kode. Pada suatu waktu yang diberikan, harus hanya satu thread yang dapat memegang lock dan dengan cara demikian mempunyai akses ke sumber daya terbagi-pakai. Lock seperti ini mengimplementasikan mutual exclusion.
Suatu thread harus memperoleh object lock yang diasosiasikan dengan suatu sumber daya terbagi-pakai, sebelum ia dapat memasuki sumber daya terbagi-pakai tersebut. Sistem runtime memastikan bahwa tidak ada thread lain yang dapat memasuki sumber daya terbagi-pakai jika suatu thread sudah memegang (hold) object lock yang diaosiasikan dengan sumber daya terbagi-pakai tersebut. Jika suatu thread tidak dapat dengan segera mendapatkan object lock,maka ia harus menunggu sampai lock tersedia. Pada saat suatu thread berada di dalam suatu sumber daya berbagi-pakai, sistem
runtime memastikan bahwa object lock juga dilepaskan. Jika suatu thread lain sedang menunggu object lock ini, ia dapat diproses untuk mendapatkan lock agar memperoleh akses ke sumber daya terbagi-pakai tersebut.
Kelas juga mempunyai suatu lock spesifik kelas yang bersifat analog dengan object lock. Lock demikian sesungguhnya merupakan lock pada obyek java.lang.Class yang berasosiasi dengan kelas tersebut. Diberikan suatu kelas A, referensi A.kelas menyatakan obyek kelas unik ini. Class lock tersebut digunakan dengan cara yang sama seperti object lock untuk mengimplementasikan mutual exclusion.
Terdapat 2 (dua) bagian kode yang dapat dikenakan sinkronisasi di dalam Java: • Synchronized method
Synchronized statement sama dengan synchronized method. Synchronized statement hanya dapat dieksekusi setelah suatu thread memperoleh lock terhadap obyek atau kelas yang dirujuk dalam pernyataan tersinkronisasi (synchronized statement).
• Synchronized block
- Upaya agar kode tertentu dijalankan secara berurutan dengan jaminan kode tersebut tidak akan dijalankan oleh yang lain dalam waktu bersamaan.
- Jika sinkronisasi diterapkan dalam metode, dipastikan bahwa seluruh kode di dalam metode tersebut dijalankan tanpa diinterupsi oleh yang lain.
Contoh:
// nama file : TesSinkron.java public class TesSinkron {
public static void main (String [] args) { Mobil m1 = new Mobil("M-1");
Mobil m2 = new Mobil("M-2"); m1.start();
m2.start(); } }
class Mobil extends Thread { // konstruktor
super (id); }
// Mendefinisikan sendiri run() public void run() {
String nama = getName(); SinkronisasiKeluaran.info(nama);
} }
class SinkronisasiKeluaran {
public static synchronized void info(String nama){ for (int i=0; i<5; i++) {
try { Thread.sleep(1000); } catch(InterruptedException ie) { System.out.println("Terinterupsi"); }
System.out.println("Thread " + nama + ":Posisi" + i ); } } }
Komunikasi Antar Thread
Thread adalah rangkaian eksekusi dari sebuah aplikasi java dan setiap program java minimal memiliki satu buah thread. Sebuah thread bisa berada di salah satu dari 4 status, yaitu new, runnable, blocked, dan dead.
New, Thread yang berada di status ini adalah objek dari kelas Thread yang baru dibuat, yaitu saat instansiasi objek dengan statement new. Saat thread berada di status new,belum ada sumber daya yang dialokasikan, sehingga thread belum bisa menjalankan perintah apapun.
Runnable. Agar thread bisa menjalankan tugasnya, method start() dari kelas Thread harus dipanggil. Ada dua hal yang terjadi saat pemanggilan method start(), yaitu alokasi memori untuk thread yang dibuat dan pemanggilan method run(). Saat method run() dipanggil, status thread berubah menjadi runnable, artinya thread tersebut sudah memenuhi syarat untuk dijalankan oleh JVM. Thread yang sedang berjalan juga berada di status runnable.
Blocked. Sebuah thread dikatakan berstatus blocked atau terhalang jika terjadi blocking statement, misalnya pemanggilan method sleep(). sleep() adalah suatu method yang menerima argumen bertipe integer dalam bentuk milisekon. Argumen tersebut menunjukkan seberapa lama thread akan “tidur”. Selain sleep(), dulunya dikenal method suspend(), tetapi sudah disarankan untuk tidak digunakan lagi karena mengakibatkan terjadinya deadlock. Thread akan menjadi runnable kembali jika interval method sleep()-nya sudah berakhir, atau pemanggilan method resume() jika untuk menghalangi thread tadi digunakan method suspend()
Dead. Sebuah thread berada di status dead bila telah keluar dari method run(). Hal ini bisa terjadi karena thread tersebut memang telah menyelesaikan pekerjaannya di method run(), maupun karena adanya pembatalan thread. Status jelas dari sebuah thread tidak dapat diketahui, tetapi method isAlive() mengembalikan nilai boolean untuk mengetahui apakah thread tersebut dead atau tidak.
Pembentukan Thread dalam java
Untuk membuat thread dalam java terdapat dua cara : Extends class Thread
Untuk menjalankan thread, dapat dilakukan dengan memanggil method start(). Saat start() dijalankan, maka sebenarnya method run() dari class akan dijalankan. Jadi untuk membuat thread, harus mendefinisikan method run() pada definisi class. Konstruktor dari cara ini adalah :
SubThread namaObject = new SubThread(); namaObject.start();
Implements interface Runnable
Cara ini merupakan cara yang paling sederhana dalam membuat thread. Runnable merupakan unit abstrak, yaitu kelas yang mengimplementasikan interface ini hanya cukup
mengimplementasikan fungsi run(). Dalam mengimplementasi fungsi run(), kita akan
MyThread myObject= new MyThread(); Thread namaObject = new Thread(myObject);
Atau dengan cara singkat seperti : New Thread(new ObjekRunnable());
MyThread merupakan class yang mengimplementasikan interface dari Runnable, dan object dari class MyThread akan menjadi parameter instansi object class Thread.
Terdapat macam-macam method dalam komunikasi antar thread, yaitu:
Method wait() menyebabkan thread terakhir yang mengakses obyek melepaskan kunci obyek dan menunggu sampai thread lain yang mengambil kunci obyek tersebut melepaskannya kembali ke obyek. Terdapat 2 jenis method wait(), yaitu :
a. Wait()menunggu sampai waktu tak berhingga sampai ada thread yang menyerahkan kunci obyek kepada obyek bersangkutan.
b. Wait ( long timeout ) menunggu sampai timeout milidetik.
Method notify() akan menyebabkan thread pemegang kunci obyek melepaskan kunci obyek dan obyek pemilik kunci memilih salah satu thread pada state BLOCKED in object’s wait pool untuk diubah state-nya ke BLOCKED in object’s lock pool.
Method notifyAll() akan menyebabkan thread pemegang kunci obyek melepaskan kunci obyek dan obyek pemilik kunci memindahkan semua thread yang berada pada state BLOCK in object’s wait pool ke state BLOCKED in object’s lock pool.
Method suspend() berbeda dengan stop(). Method ini mengambil thread tertentu dan menyebabkannya berhenti tanpa menghancurkan thread di bawahnya atau keadaan thread yang berjalan sebelumnya. Jika suatu thread di-suspend, panggil method resume() padathread yang sama untuk menjalankannya lagi.
Resume() method ini digunakan untuk menghidupkan method yang di-suspend. Tidak ada jaminan bahwa thread yang dijalankan kembali akan berjalan dengan baik karena mungkin sudah ada thread dengan prioritas lebih tinggi yang berjalan
Stop() method ini menyebabkan thread segera berhenti. Ini sering dijadikan cara tercepat untuk mengakhiri suatu thread khususnya jika method ini dieksekusi pada thread yang berlaku. Pada kasus ini, baris program setelah pemanggilan method stop() tidak pernah dieksekusi karena konteks jalinan musnah sebelum stop() selesai.
Dalam Java kita dapat membuat prioritas suatu thread relative terhadapa thread yang lain. Sehingga thread yang mempunyai prioritas lebih tinggi mempunyai kesempatan lebih besar untuk mengakses suatu sources
Java Virtual Machine memilih thread yang runnable dengan prioritas tertinggi. Semua thread java mempunyai prioritas dari 1 sampai 10. Prioritas tertinggi 10 dan berakhir dengan 1 sebagai prioritas terendah. Sedangkan prioritas normal adalah 5.
Thread.MIN_PRIORITY = thread dengan prioritas terendah. Thread.MAX_PRIORITY = thread dengan prioritas tertinggi. Thread.NORM_PRIORITY = thread dengan prioritas normal.
Saat thread baru dibuat ia mempunyai prioritas yang sama dengan thread yang menciptakannya. Prioritas thread dapat diubah dengan menggunakan setpriority() method. Bagaimanapun juga sebuah thread yang berjalan bersama-sama kadang-kadang membutuhkan resource atau method dari luar, butuh untuk berkomunikasi satu dengan yang lain sehingga dapat mengetahui status dan aktifitas mereka
Contoh: Permasalahan Produser-Konsumer 1 class TwoStrings {
2 static void print(String str1, String str2) { 3 System.out.print(str1);
4 try {
5 Thread.sleep(500);
6 } catch (InterruptedException ie) { 7 }
8 System.out.println(str2); 9 }
10 }
11 class PrintStringsThread implements Runnable { 12 Thread thread;
13 String str1, str2;
14 PrintStringsThread(String str1, String str2) { 15 this.str1 = str1;
16 this.str2 = str2;
17 thread = new Thread(this); 18 thread.start();
19 }
20 public void run() {
21 TwoStrings.print(str1, str2); 22 }
23 }
24 class TestThread {
25 public static void main(String args[]) {
26 new PrintStringsThread("Hello ", "there."); 27 new PrintStringsThread("How are ", "you?");
28 new PrintStringsThread("Thank you ",
29 "very much!"); 30 }
31 }
Contoh hasil :
Hello How are Thank you there. you? very much!
Mengunci sebuah object:
- Untuk memastikan bahwa hanya satu thread yang mendapatkan hak akses kedalam method tertentu
- Java memperbolehkan penguncian terhadap sebuah object termasuk method-method-nya dengan menggunakan monitor
o Object tersebut akan menjalankan sebuah monitor implicit pada saat object dari method sinkronisasi dipanggil
o Sekali object tersebut dimonitor, monitor tersebut akan memastikan bahwa tidak ada thread yang akan mengakses object yang sama
- Sinkronisasi sebuah method:
o Menggunakan keyword synchronized
o Dapat menjadi header dari pendefinisian method
o Dapat mensinkronisasi object dimana method tersebut menjadi anggota dari
synchronized (<object>) {
//statements yang akan disinkronisasikan }
Contoh Synchronized Pertama 1 class TwoStrings {
2 synchronized static void print(String str1, 3 String str2) { 4 System.out.print(str1);
5 try {
6 Thread.sleep(500);
7 } catch (InterruptedException ie) { 8 }
9 System.out.println(str2); 10 }
11 }
12 class PrintStringsThread implements Runnable { 13 Thread thread;
14 String str1, str2;
15 PrintStringsThread(String str1, String str2) { 16 this.str1 = str1;
17 this.str2 = str2;
18 thread = new Thread(this); 19 thread.start();
20 }
21 public void run() {
22 TwoStrings.print(str1, str2); 23 }
24 }
25 class TestThread {
26 public static void main(String args[]) {
27 new PrintStringsThread("Hello ", "there."); 28 new PrintStringsThread("How are ", "you?"); 29 new PrintStringsThread("Thank you ",
30 "very much!"); 31 } 32 } Contoh Hasil: Hello there. How are you?
Thank you very much! Contoh Synchronized Kedua : 1 class TwoStrings {
2 static void print(String str1, String str2) { 3 System.out.print(str1);
4 try {
5 Thread.sleep(500);
6 } catch (InterruptedException ie) { 7 }
8 System.out.println(str2); 9 }
10 }
11 class PrintStringsThread implements Runnable { 12 Thread thread; 13 String str1, str2; 14 TwoStrings ts; 15 PrintStringsThread(String str1, String str2, 16 TwoStrings ts) { 17 this.str1 = str1; 18 this.str2 = str2; 19 this.ts = ts;
20 thread = new Thread(this); 21 thread.start();
22 }
23 public void run() { 24 synchronized (ts) { 25 ts.print(str1, str2); 26 } 27 } 28 } 29 class TestThread {
30 public static void main(String args[]) { 31 TwoStrings ts = new TwoStrings();
32 new PrintStringsThread("Hello ", "there.", ts); 33 new PrintStringsThread("How are ", "you?", ts); 34 new PrintStringsThread("Thank you ",
35 "very much!", ts); 36 }}
KOMUNIKASI ANTAR THREAD: METHODS
Methods untuk komunikasi Interthread
public final void wait()
Menyebabkan thread ini menunggu sampai thread yang lain memanggil notify atau
notifyAll method dari object ini. Hal ini dapat menyebabkan InterruptedException. public final void notify()
Membangunkan thread yang telah memanggil method wait dari object yang sama. public final void notifyAll()
Membangunkan semua thread yang telah memanggil method wait dari object yang sama.
Contoh Produsen-Konsumen 1 class SharedData { 2 int data;
3 synchronized void set(int value) {
4 System.out.println("Generate " + value); 5 data = value;
6 }
7 synchronized int get() {
8 System.out.println("Get " + data); 9 return data;
10 } 11 }
12 class Producer implements Runnable { 13 SharedData sd;
14 Producer(SharedData sd) { 15 this.sd = sd;
16 new Thread(this, "Producer").start(); 17 }
18 public void run() {
19 for (int i = 0; i < 10; i++) {
20 sd.set((int)(Math.random()*100)); 21 }
22 } 23 }
24 class Consumer implements Runnable { 25 SharedData sd;
26 Consumer(SharedData sd) { 27 this.sd = sd;
28 new Thread(this, "Consumer").start(); 29 }
30 public void run() {
31 for (int i = 0; i < 10 ; i++) { 32 sd.get();
33 } 34 } 35 }
36 class TestProducerConsumer {
37 public static void main(String args[]) 38 throws Exception {
39 SharedData sd = new SharedData(); 40 new Producer(sd);
41 new Consumer(sd); 42 }}
Contoh hasil
Generate 8 Generate 49 Get 85
Generate 45 Get 49 Get 85
Generate 52 Generate 35 Get 85
Get 65 Generate 39 Get 35
Generate 23 Get 39 Get 35
Get 23 Generate 85
Contoh Produsen-Konsumen yang telah diperbaiki 1 class SharedData {
2 int data;
3 boolean valueSet = false;
4 synchronized void set(int value) {
5 if (valueSet) { //hanya dihasilkan jika mempumyai sebuah nilai
6 try { 7 wait();
8 } catch (InterruptedException ie) { 9 } 10 } 11 System.out.println("Generate " + value); 12 data = value; 13 valueSet = true; 14 notify(); 15 }
16 synchronized int get() { 17 if (!valueSet) {
18 //producer belum memiliki suatu nilai 19 try {
20 wait();
21 } catch (InterruptedException ie) { 22 } 23 } 24 System.out.println("Get " + data); 25 valueSet = false; 26 notify(); 27 return data; 28 } 29 } 30
31 /* Bagian kode tertentu tidak berubah. */
Contoh hasil :
Generate 76 Generate 48 Generate 65
Get 76 Get 48 Get 65
Generate 25 Generate 29 Generate 38
Get 25 Get 29 Get 38
Generate 34 Generate 26 Generate 46
Get 34 Get 26 Get 46
Generate 84 Get 84
Generate 86 Get 86
Ringkasan
Sinkronisasi
Mengunci sebuah Object Keyword synchronized
Method header Object
Komunikasi Antar Thread (Interthread) Methods
wait notify notifyAll