Sebelum Java 5, kata kunci yang disinkronkan digunakan untuk mengimplementasikan fungsi kunci.
Kata kunci yang disinkronkan dapat digunakan sebagai pengubah (metode sinkronisasi) atau sebagai pernyataan dalam suatu fungsi (blok kode yang disinkronkan).
Untuk menguasai sinkronisasi, kuncinya adalah menguasai penggunaan benda itu sebagai kunci. Untuk metode non-statis (metode anggota) dari suatu kelas, ini berarti mendapatkan kunci instance objek; Untuk metode statis (metode kelas) dari suatu kelas, perlu untuk mendapatkan kunci objek kelas; Untuk blok kode sinkron, perlu untuk menentukan kunci objek mana yang diperoleh. Metode non-statis yang disinkronkan dapat dianggap sebagai blok kode yang disinkronkan (ini) {...} yang berisi seluruh metode.
Apakah itu blok kode sinkron atau metode sinkronisasi, hanya satu utas yang dapat masuk pada satu waktu (paling banyak satu utas menjalankan segmen kode pada saat yang sama.), Dan jika utas lain mencoba masuk (apakah itu blok sinkron yang sama atau blok sinkronisasi yang berbeda), JVM akan menggantungnya (dimasukkan ke dalam kumpulan kunci menunggu). Struktur ini disebut bagian kritis dalam teori konkurensi.
Dalam JVM, untuk meningkatkan efisiensi, setiap utas yang berjalan pada saat yang sama akan memiliki salinan cache data yang diproses. Ketika kami menggunakan sinkronisasi untuk sinkronisasi, yang benar -benar disinkronkan adalah blok memori yang mewakili objek yang terkunci di utas yang berbeda (data salin akan tetap disinkronkan dengan memori utama. Sekarang kita tahu mengapa sinkronisasi kata digunakan). Sederhananya, setelah blok sinkronisasi atau metode sinkronisasi dieksekusi, modifikasi apa pun yang dibuat untuk objek yang terkunci harus ditulis kembali ke memori utama sebelum melepaskan kunci; Setelah memasukkan blok sinkronisasi dan mendapatkan kunci, data objek yang terkunci dibaca dari memori utama, dan salinan data utas yang menahan kunci harus disinkronkan dengan tampilan data di memori utama.
Berikut ini adalah contoh spesifik untuk menggambarkan berbagai situasi disinkronkan.
Metode sinkronisasi yang disinkronkan
Pertama, mari kita lihat contoh metode sinkronisasi:
Kelas Publik SynchronizedTest1 Memperluas Thread {private disinkronkan void testsynchronizedMethod () {for (int i = 0; i <10; i ++) {System.out.println (thread.currentThread (). getName () + "testsynchronizedMethod:" + i); coba {thread.sleep (100); } catch (InterruptedException e) {E.PrintStackTrace (); }}} @Override public void run () {testsynchronizedMethod (); } public static void main (string [] args) {synchronizedTest1 t = new SynchronizedTest1 (); t.start (); t.testsynchronizedMethod (); }}Menjalankan output program:
TestsynchronizedMethod: 0 TestsynchronizedMethod utama: 1 testsynchronizedMethod: 2 testsynchronizedMethod utama: 3 testsynchronizedMethod: 4 testsynchronizedMethod: 5 TestSynizedMethod: 6 Main testsynchronizedMethod: 5 Mauncerieshron: 6 Main TestsynchonizedMethod: 5 TestSynchronizedMethod: 9 Thread-0 testsynchronizedMethod: 0 Thread-0 testsynchronizedMethod: 1 Thread-0 testsynchronizedMethod: 2 thread-0 testsynchronizedMethod: 3 thread-0 testsynchonizedMethod: 4 Thread-0 testsynchonized: 3 thread-0 testsynchonized: 4 Thread-0 testsynchonized: 5 Thread-0 TestSynChronized: 4 Thread-0 Testsynchonized: TestSynchronizedMethod: 7 Thread-0 testsynchronizedMethod: 8 Thread-0 testsynchronizedMethod: 9
Anda dapat melihat bahwa metode testsynchronizedMethod dieksekusi secara serempak antara dua utas.
Jika metode utama dimodifikasi ke yang berikut, kedua utas tersebut tidak dapat mengeksekusi secara sinkron, karena monitor sinkronisasi kedua utas tersebut bukan objek yang sama dan tidak dapat memainkan peran sinkron.
public static void main (string [] args) {thread t = new synchronizedTest1 (); t.start (); Thread t1 = new sinchronizedTest1 (); t1.start (); }Hasil output adalah sebagai berikut:
Thread-0 testsynchronizedMethod: 0 thread-1 testsynchronizedmethod: 0 thread-0 testsynchronizedMethod: 1 thread-1 testsynchronizedMethod: 1 thread-0 testsynchronizedMethod: 2 thread-1 testsynchonzethod: 2 thread-0 testsynchonizedMethod: 3 Thread-1-nabati: 3 thread-nabi: 2 thread-thread-0 testsynchronized: 3 thread-1 testsynchonize: 2 thread-0 testsynchronizedshod: 3 thread-nabutan-3-nabati: 3 thread-nabi-nabi-nabi: testsynchronizedMethod: 4 thread-1 testsynchronizedMethod: 4 thread-0 testsynchronizedMethod: 5 thread-1 testsynchronizedMethod: 5 thread-0 testsynchronizedMethod: 6 thread-1 testsynchronizedMethod: 6 Thread-0 testsynchronizedMethod: 7 Thread-1 TestSynchronizedMethod: 8 Thread-1 testsynchronizedMethod: 8 Thread-0 testsynchronizedMethod: 9 Thread-1 testsynchronizedMethod: 9
Jika metode utama yang dimodifikasi dapat dijalankan secara sinkron antara dua utas, metode TestSynchronizedMethod perlu dinyatakan sebagai metode statis, sehingga monitor kedua utas tersebut adalah objek yang sama (objek kelas) dan dapat dieksekusi secara sinkron. Kode yang dimodifikasi terlihat seperti ini:
Kelas Publik SynchronizedTest1 memperluas thread {private static static void testsynchronizedMethod () {for (int i = 0; i <10; i ++) {System.out.println (thread.currentThread (). getName () + "testsynchronizedMethod:" + i); coba {thread.sleep (100); } catch (InterruptedException e) {E.PrintStackTrace (); }}} @Override public void run () {testsynchronizedMethod (); } public static void main (string [] args) {thread t = new synchronizedTest1 (); t.start (); Thread t1 = new sinchronizedTest1 (); t1.start (); }}Hasil output adalah sebagai berikut:
Thread-0 testsynchronizedMethod: 0 thread-0 testsynchronizedmethod: 1 thread-0 testsynchronizedMethod: 2 thread-0 testsynchronizedMethod: 3 thread-0 testsynchronizedMethod-thread-0 testsynochod: 5 Thread-0 testsynchonized-0 testsynchronizedMethod: 8 Thread-0 testsynchronizedMethod: 9 thread-1 testsynchronizedMethod: 0 thread-1 testsynchronizedMethod: 1 thread-1 testsynchronizedMethod: 2 thread-1 testsynchronizedMethod: 3 thread-1 testsynchronizedMethod: 4 Thread-1 testsymrronizedMethod: 3 thread-1 testsynchronizedMethod: 4 thread-1 testsymonMethod: 3 thread-1 testsynchonizedMethod: 4 thread-1 threadmonMhod- TestSynchronizedMethod: 7 Thread-1 testsynchronizedMethod: 8 Thread-1 testsynchronizedMethod: 9
Situasi blok sinkron mirip dengan metode sinkronisasi, kecuali bahwa blok sinkron mengurangi granularitas kontrol sinkronisasi, yang dapat dengan lebih baik mengerahkan efisiensi eksekusi paralel multi-threaded.
Gunakan objek ini untuk mengontrol sinkronisasi antara instance objek yang sama:
Kelas Publik SynchronizedTest2 memperluas thread {private void testsynchronizedBlock () {disinkronkan (this) {for (int i = 0; i <10; i ++) {System.out.println (thread.currentThread (). GetName () + "testsynchronizedBlock:" + i); coba {thread.sleep (100); } catch (InterruptedException e) {E.PrintStackTrace (); }}}} @Override public void run () {testsynchronizedBlock (); } public static void main (string [] args) {synchronizedTest2 t = new synchronizedTest2 (); t.start (); t.testsynchronizedBlock (); }}Hasil output:
main testSynchronizedBlock:0 main testSynchronizedBlock:1 main testSynchronizedBlock:2 main testSynchronizedBlock:3 main testSynchronizedBlock:4 main testSynchronizedBlock:5 main testSynchronizedBlock:6 main testSynchronizedBlock:7 main testSynchronizedBlock:8 main testSynchronizedBlock:9 Thread-0 testSynchronizedBlock:0 Thread-0 testSynchronizedBlock:1 Thread-0 testSynchronizedBlock:2 Thread-0 testSynchronizedBlock:3 Thread-0 testSynchronizedBlock:4 Thread-0 testSynchronizedBlock:5 Thread-0 testSynchronizedBlock:6 Thread-0 testSynchronizedBlock:7 Thread-0 testSynchronizedBlock:8 Thread-0 TestSynchronizedBlock: 9
Gunakan objek kelas untuk mengontrol sinkronisasi antara berbagai contoh:
Kelas Publik SynchronizedTest2 memperluas thread {private void testsynchronizedBlock () {disinkronkan (disinkronkantest2.class) {for (int i = 0; i <10; i ++) {System.out.println (thread.currentThread (). coba {thread.sleep (100); } catch (InterruptedException e) {E.PrintStackTrace (); }}}} @Override public void run () {testsynchronizedBlock (); } public static void main (string [] args) {thread t = new synchronizedTest2 (); t.start (); Thread t2 = new SynchronizedTest2 (); t2.start (); }}Hasil output:
Thread-0 testsynchronizedBlock: 0 thread-0 testsynchronizedblock: 1 thread-0 testsynchronizedBlock: 2 thread-0 testsynchronizedblock: 3 thread-0 testsynchronizedblock: 4 thread-0 testsynchronizedblock: 5 thread-0 testsynchronizedblock: 6 Thread-0 Thread-0 testSynchronizedBlock:9 Thread-1 testSynchronizedBlock:0 Thread-1 testSynchronizedBlock:1 Thread-1 testSynchronizedBlock:2 Thread-1 testSynchronizedBlock:3 Thread-1 testSynchronizedBlock:4 Thread-1 testSynchronizedBlock:5 Thread-1 testSynchronizedBlock:6 Thread-1 testSynchronizedBlock:7 Thread-1 TestSynchronizedBlock: 8 Thread-1 testsynchronizedBlock: 9
Saat menggunakan kata kunci yang disinkronkan untuk kontrol sinkronisasi, Anda harus memahami monitor objek. Hanya proses yang mendapatkan monitor yang dapat berjalan, dan segala sesuatu yang perlu ditunggu untuk mendapatkan monitor. Objek non-nol dapat digunakan sebagai monitor objek. Saat disinkronkan bertindak pada suatu metode, instance objek terkunci; Saat bertindak pada metode statis, instance objek terkunci sesuai dengan objek.
Metode sinkron untuk dua utas untuk mengakses objek secara bersamaan
Ketika dua utas bersamaan mengakses metode sinkron dari objek yang sama, hanya satu utas yang dapat dijalankan. Utas lain harus menunggu utas saat ini untuk menjalankan ini sebelum dapat dieksekusi.
kelas publik twothread {public static void main (string [] args) {final twothread twothread = twothread baru (); Utas t1 = utas baru (runnable baru () {public void run () {twothread.syncmethod ();}}, "a"); Utas t2 = utas baru (runnable baru () {public void run () {twothread.syncmethod ();}}, "b"); t1.start (); t2.start (); } public disinkronkan void syncmethod () {for (int i = 0; i <5; i ++) {System.out.println (thread.currentThread (). getName () + ":" + i); coba {thread.sleep (500); } catch (InterruptedException IE) {}}}}Hasil output:
A: 0A: 1A: 2A: 3A: 4B: 0B: 1B: 2B: 3B: 4
Metode sinkronisasi dua objek diakses oleh dua utas
Dalam hal ini, disinkronkan tidak berfungsi, seperti halnya metode biasa. Karena kunci yang sesuai adalah objek masing -masing.
kelas publik TwoObject {public static void main (string [] args) {final twoObject object1 = new twoObject (); Thread t1 = utas baru (runnable baru () {public void run () {objek1.syncmethod ();}}, "Object1"); t1.start (); Final TwoObject Object2 = new TwoObject (); Thread t2 = utas baru (runnable baru () {public void run () {public void run () {object2.syncmethod ();}}, "Object2"); t2.start (); } public disinkronkan void syncmethod () {for (int i = 0; i <5; i ++) {System.out.println (thread.currentThread (). getName () + ":" + i); coba {thread.sleep (500); } catch (InterruptedException IE) {}}}}Salah satu output yang mungkin:
Object2: 0Object1: 0Object1: 1Object2: 1Object2: 2Object1: 2Object2: 3Object1: 3Object1: 4Object2: 4
Dua utas mengakses metode statis yang disinkronkan
Dalam hal ini, karena kelas terkunci, kapan saja, hanya satu utas yang dapat menjalankan metode statis.
Mengakses metode sinkron dan metode asinkron secara bersamaan ketika satu utas mengakses satu metode sinkronisasi suatu objek, utas lain masih dapat mengakses metode asinkron dalam objek itu.
SyncandNoSync {public static void main (string [] args) {final syncandnosync syncandnosync = new syncandnosync (); Thread t1 = utas baru (runnable baru () {public void run () {syncandnosync.syncmethod ();}}, "a"); t1.start (); Thread t2 = utas baru (runnable baru () {public void run () {syncandnosync.nosyncmethod ();}}, "b"); t2.start (); } public Synchronized void syncmethod () {for (int i = 0; i <5; i ++) {System.out.println (thread.currentThread (). getName () + "di syncmethod ():" + i); coba {thread.sleep (500); } catch (InterruptedException IE) {}}} public void nosyncmethod () {for (int i = 0; i <5; i ++) {System.out.println (thread.currentThread (). getName () + "di nosyncmethod ():" + i); coba {thread.sleep (500); } catch (InterruptedException IE) {}}}}Satu kemungkinan output:
B at noSyncMethod(): 0A at syncMethod(): 0B at noSyncMethod(): 1A at syncMethod(): 1B at noSyncMethod(): 2A at syncMethod(): 2B at noSyncMethod(): 3A at syncMethod(): 3A at syncMethod(): 4B at nosyncmethod (): 4
Metode sinkronisasi yang berbeda untuk mengakses objek yang sama
Ketika utas mengakses metode sinkronisasi A dari suatu objek, utas lain akses ke semua metode sinkronisasi lain dalam objek akan diblokir. Karena utas pertama telah memperoleh kunci objek dan utas lainnya tidak dapat memperoleh kunci, meskipun mengakses metode yang berbeda, tidak mendapatkan kunci dan tidak dapat mengaksesnya.
kelas publik twoSyncmethod {public static void main (string [] args) {final twoSyncmethod twoSyncmethod = twoSyncmethod baru (); Thread t1 = utas baru (runnable baru () {public void run () {twoSyncmethod.syncmethod1 ();}}, "a"); t1.start (); Thread t2 = utas baru (runnable baru () {public void run () {twoSyncmethod.syncmethod2 ();}, "b"); t2.start (); } public disinkronkan void syncmethod1 () {for (int i = 0; i <5; i ++) {System.out.println (thread.currentThread (). getName () + "di syncmethod1 ():" + i); coba {thread.sleep (500); } catch (InterruptedException IE) {}}} public disinkronkan void syncmethod2 () {for (int i = 0; i <5; i ++) {System.out.println (thread.currentThread (). GetName () + "at syncmethod2 ():" + i); coba {thread.sleep (500); } catch (InterruptedException IE) {}}}}Hasil output:
A AT SyncMethOD1 (): 0A AT SYNCMETHOD1 (): 1A AT SYNCMETHOD1 (): 2A AT SYNCMETHOD1 (): 3A AT SYNCMETHOD1 (): 4B AT SYNCMETHOD2 (): 0B AT SYNCMETHOD2 (): 1B AT SYNCMETHOD2 (): 2B AT SYNCMETHOD2 (): 1B AT SYNCMETHOD2 (); syncmethod2 (): 4