1. Penggunaan dasar sinkronisasi
Sinkronisasi adalah metode yang paling umum digunakan untuk menyelesaikan masalah konkurensi di Java dan metode termudah. Sinkronisasi memiliki tiga fungsi utama: (1) Pastikan utas kode sinkronisasi akses yang saling eksklusif (2) memastikan bahwa modifikasi variabel bersama dapat terlihat tepat waktu (3) secara efektif menyelesaikan masalah pemesanan ulang. Sinkronisasi memiliki tiga penggunaan yang disinkronkan:
(1) Metode memodifikasi biasa
(2) memodifikasi metode statis
(3) Ubah blok kode
Selanjutnya, saya akan menggunakan beberapa contoh program untuk menggambarkan ketiga metode penggunaan ini (demi perbandingan, kecuali untuk berbagai metode penggunaan yang disinkronkan, tiga kode lainnya pada dasarnya konsisten).
1. Tidak ada sinkronisasi:
Cuplikan Kode 1:
paket com.paddx.test.concurrent; kelas publik SynchronizedTest {public void Method1 () {System.out.println ("Metode 1 Start"); coba {System.out.println ("Metode 1 Execute"); Thread.sleep (3000); } catch (InterruptedException e) {E.PrintStackTrace (); } System.out.println ("Metode 1 End"); } public void method2 () {System.out.println ("Metode 2 Start"); coba {System.out.println ("Metode 2 Execute"); Thread.sleep (1000); } catch (InterruptedException e) {E.PrintStackTrace (); } System.out.println ("Metode 2 End"); } public static void main (string [] args) {final synchronizedTest test = new synchronizedTest (); utas baru (runnable baru () {@Override public void run () {test.method1 ();}}). start (); utas baru (runnable baru () {@Override public void run () {test.method2 ();}}). start (); }}Hasil eksekusi adalah sebagai berikut: Thread 1 dan Thread 2 Masukkan status eksekusi secara bersamaan. Thread 2 mengeksekusi lebih cepat dari utas 1, jadi utas 2 dijalankan terlebih dahulu. Dalam proses ini, utas 1 dan utas 2 dijalankan secara bersamaan.
Metode 1 Mulai
Metode 1 Eksekusi
Metode 2 Mulai
Metode 2 mengeksekusi
Metode 2 Akhir
Metode 1 Akhir
2. Sinkronisasi metode umum:
Cuplikan Kode Dua:
Paket com.paddx.test.concurrent; kelas publik SynchronizedTest {public disinkronkan void method1 () {System.out.println ("Metode 1 start"); coba {System.out.println ("Metode 1 Execute"); Thread.sleep (3000); } catch (InterruptedException e) {E.PrintStackTrace (); } System.out.println ("Metode 1 End"); } Metode void yang disinkronkan publik () {System.out.println ("Metode 2 Start"); coba {System.out.println ("Metode 2 Execute"); Thread.sleep (1000); } catch (InterruptedException e) {E.PrintStackTrace (); } System.out.println ("Metode 2 End"); } public static void main (string [] args) {final synchronizedTest test = new synchronizedTest (); utas baru (runnable baru () {@Override public void run () {test.method1 ();}}). start (); utas baru (runnable baru () {@Override public void run () {test.method2 ();}}). start (); }}Hasil eksekusi adalah sebagai berikut. Setelah membandingkannya dengan segmen kode, dapat dilihat dengan jelas bahwa Thread 2 perlu menunggu pelaksanaan Method1 dari Thread 1 untuk diselesaikan sebelum mulai menjalankan metode Method2.
Metode 1 Mulai
Metode 1 Eksekusi
Metode 1 Akhir
Metode 2 Mulai
Metode 2 mengeksekusi
Metode 2 Akhir
3. Sinkronisasi Metode Statis (Kelas)
Cuplikan Kode Tiga:
paket com.paddx.test.concurrent; Public Class SynchronizedTest {public static static void method1 () {System.out.println ("Metode 1 start"); coba {System.out.println ("Metode 1 Execute"); Thread.sleep (3000); } catch (InterruptedException e) {E.PrintStackTrace (); } System.out.println ("Metode 1 End"); } public static static void method2 () {System.out.println ("Metode 2 Start"); coba {System.out.println ("Metode 2 Execute"); Thread.sleep (1000); } catch (InterruptedException e) {E.PrintStackTrace (); } System.out.println ("Metode 2 End"); } public static void main (string [] args) {final synchronizedTest test = new synchronizedTest (); final SynchronizedTest test2 = new SynchronizedTest (); utas baru (runnable baru () {@Override public void run () {test.method1 ();}}). start (); utas baru (runnable baru () {@Override public void run () {test2.method2 ();}}). start (); }}Hasil eksekusi adalah sebagai berikut. Sinkronisasi metode statis pada dasarnya adalah sinkronisasi kelas (metode statis pada dasarnya adalah metode kelas, bukan metode pada objek). Oleh karena itu, bahkan jika tes dan test2 milik objek yang berbeda, keduanya termasuk dalam contoh kelas SynchronizedTest, sehingga Method1 dan Method2 hanya dapat dieksekusi secara berurutan, dan tidak dapat dieksekusi secara bersamaan.
Metode 1 Mulai
Metode 1 Eksekusi
Metode 1 Akhir
Metode 2 Mulai
Metode 2 mengeksekusi
Metode 2 Akhir
4. Sinkronisasi Blok Kode
Kode Cuplikan Empat:
paket com.paddx.test.concurrent; kelas publik SynchronizedTest {public void Method1 () {System.out.println ("Metode 1 Start"); coba {disinkronkan (this) {System.out.println ("Metode 1 Execute"); Thread.sleep (3000); }} catch (InterruptedException e) {E.PrintStackTrace (); } System.out.println ("Metode 1 End"); } public void method2 () {System.out.println ("Metode 2 Start"); coba {disinkronkan (this) {System.out.println ("Metode 2 Execute"); Thread.sleep (1000); }} catch (InterruptedException e) {E.PrintStackTrace (); } System.out.println ("Metode 2 End"); } public static void main (string [] args) {final synchronizedTest test = new synchronizedTest (); utas baru (runnable baru () {@Override public void run () {test.method1 ();}}). start (); utas baru (runnable baru () {@Override public void run () {test.method2 ();}}). start (); }}Hasil eksekusi adalah sebagai berikut. Meskipun kedua Thread 1 dan Thread 2 masukkan metode yang sesuai dan mulai eksekusi, Thread 2 perlu menunggu eksekusi blok sinkronisasi di Thread 1 untuk diselesaikan sebelum memasukkan blok sinkronisasi.
Metode 1 Mulai
Metode 1 Eksekusi
Metode 2 Mulai
Metode 1 Akhir
Metode 2 mengeksekusi
Metode 2 Akhir
2. Prinsip yang disinkronkan
Jika Anda masih memiliki pertanyaan tentang hasil eksekusi di atas, jangan khawatir. Pertama -tama mari kita pahami prinsip sinkronisasi, dan kemudian lihat kembali pertanyaan -pertanyaan di atas untuk dilihat secara sekilas. Pertama -tama mari kita lihat bagaimana kode yang disinkronkan menyinkronkan blok kode dengan mendekompilasi kode berikut:
paket com.paddx.test.concurrent; kelas publik SynchronizedDemo {public void Method () {disinkronkan (this) {System.out.println ("Metode 1 start"); }}}Hasil dekompilasi:
Mengenai peran dua instruksi ini, kami secara langsung merujuk pada deskripsi dalam spesifikasi JVM:
Monitorenter:
Setiap objek dikaitkan dengan monitor. Monitor dikunci jika dan hanya jika memiliki pemilik. Utas yang mengeksekusi upaya pemantau untuk mendapatkan kepemilikan monitor yang terkait dengan objectref, sebagai berikut: • Jika jumlah masuk monitor yang terkait dengan objectref adalah nol, utasnya memasuki monitor dan menetapkan jumlah masuknya menjadi satu. Utas kemudian adalah pemilik monitor. • Jika utas sudah memiliki monitor yang terkait dengan objectref, ia masuk kembali ke monitor, meningkatkan jumlah masuknya. • Jika utas lain sudah memiliki monitor yang terkait dengan objectref, blok utas sampai jumlah masuk monitor adalah nol, maka mencoba lagi untuk mendapatkan kepemilikan.
Arti umum dari bagian ini adalah:
Setiap objek memiliki kunci monitor (monitor). Ketika monitor ditempati, itu akan dikunci. Ketika utas mengeksekusi instruksi Monitorenter, ia mencoba untuk mendapatkan kepemilikan monitor. Prosesnya adalah sebagai berikut:
1. Jika jumlah entri monitor adalah 0, utas memasuki monitor, dan kemudian menetapkan nomor masuk ke 1, utas adalah pemilik monitor.
2. Jika utas sudah memiliki monitor dan baru saja masuk kembali, jumlah masuk ke monitor ditambahkan ke 1.
3. Jika utas lain telah menempati monitor, utas memasuki status pemblokiran sampai jumlah masuknya monitor adalah 0, dan kemudian cobalah untuk mendapatkan kepemilikan monitor lagi.
Monitorexit:
Utas yang mengeksekusi monitorexit harus menjadi pemilik monitor yang terkait dengan instance yang dirujuk oleh objectref. Thread mengurangi jumlah masuk monitor yang terkait dengan objectref. Jika sebagai hasilnya, nilai jumlah entri adalah nol, utas keluar dari monitor dan bukan lagi pemiliknya. Utas lain yang memblokir untuk memasuki monitor diizinkan untuk mencoba melakukannya.
Arti umum dari bagian ini adalah:
Monitorexit yang dieksekusi oleh utas harus menjadi pemilik monitor yang sesuai dengan objectref.
Ketika instruksi dieksekusi, jumlah monitor yang masuk dikurangi dengan 1. Jika jumlah monitor yang masuk adalah 0 setelah dikurangi dengan 1, utas keluar dari monitor dan tidak lagi menjadi pemilik monitor ini. Utas lain yang diblokir oleh monitor ini dapat mencoba untuk mendapatkan kepemilikan monitor ini.
Melalui dua paragraf deskripsi ini, kita harus dapat dengan jelas melihat prinsip implementasi yang disinkronkan. Lapisan yang mendasari semantik disinkronkan diselesaikan melalui objek monitor. Bahkan, tunggu/beri tahu dan metode lain juga bergantung pada objek monitor. Inilah sebabnya mengapa hanya metode seperti Wait/Notify yang dapat dipanggil dalam blok atau metode yang disinkronkan, jika tidak, pengecualian java.lang.illegalmonitorStateException akan dilemparkan.
Mari kita lihat hasil dekompilasi dari metode sinkronisasi:
Kode Sumber:
Paket com.paddx.test.concurrent; kelas publik SynchronizedMethod {Metode void yang disinkronkan publik () {System.out.println ("Hello World!"); }}Hasil dekompilasi:
Menilai dari hasil dekompilasi, sinkronisasi metode ini tidak diselesaikan melalui instruksi Monitorenter dan Monitorexit (secara teori, itu juga dapat diimplementasikan melalui dua instruksi ini). Namun, dibandingkan dengan metode biasa, pengidentifikasi ACC_SYNCHRONIZed ditambahkan ke kumpulan konstannya. JVM mengimplementasikan sinkronisasi metode berdasarkan pengidentifikasi ini: Ketika metode ini dipanggil, instruksi panggilan akan memeriksa apakah bendera akses acc_synchronized dari metode ini diatur. Jika diatur, utas eksekusi pertama akan mendapatkan monitor, dan kemudian jalankan badan metode setelah metode berhasil dieksekusi. Setelah metode dieksekusi, monitor akan dirilis. Selama eksekusi metode, tidak ada utas lain yang bisa mendapatkan objek monitor yang sama lagi. Faktanya, tidak ada perbedaan dalam esensi, tetapi sinkronisasi metode ini adalah cara implisit untuk mencapainya tanpa perlu dilakukan melalui bytecode.
3. Penjelasan Hasil Operasi
Dengan pemahaman tentang prinsip sinkronisasi, Anda dapat dengan mudah menyelesaikannya dengan melihat program di atas.
1. Segmen Kode 2 Hasil:
Meskipun Method1 dan Method2 adalah metode yang berbeda, kedua metode disinkronkan dan dipanggil melalui objek yang sama. Oleh karena itu, sebelum menelepon, Anda perlu bersaing untuk mengunci (monitor) pada objek yang sama, sehingga Anda hanya dapat memperoleh kunci secara eksklusif. Oleh karena itu, method1 dan method2 hanya dapat dieksekusi secara berurutan.
2. Segmen Kode 3 Hasil:
Meskipun tes dan test2 milik objek yang berbeda, tes dan test2 milik berbagai contoh kelas yang sama. Karena method1 dan method2 keduanya termasuk dalam metode sinkronisasi statis, Anda perlu mendapatkan monitor pada kelas yang sama (setiap kelas hanya sesuai dengan satu objek kelas), sehingga Anda hanya dapat mengeksekusi secara berurutan.
3. Segmen Kode 4 Hasil:
Untuk sinkronisasi blok kode, pada dasarnya diperlukan untuk mendapatkan monitor objek dalam tanda kurung setelah kata kunci yang disinkronkan. Karena isi braket dalam kode ini adalah ini, dan Method1 dan Method2 dipanggil melalui objek yang sama, jadi sebelum memasukkan blok sinkronisasi, Anda perlu bersaing untuk mengunci pada objek yang sama, sehingga blok sinkronisasi hanya dapat dieksekusi secara berurutan.
Empat ringkasan
Sinkronisasi adalah metode yang paling umum digunakan untuk keamanan utas dalam pemrograman bersamaan Java, dan relatif mudah digunakan. Namun, jika kita dapat memahami prinsip -prinsipnya secara mendalam dan memiliki beberapa pemahaman tentang pengetahuan yang mendasari seperti kunci monitor, itu dapat membantu kita menggunakan kata kunci yang disinkronkan dengan benar, dan di sisi lain, itu juga dapat membantu kita lebih memahami mekanisme pemrograman konkurensi, membantu kita memilih strategi konkurensi yang lebih baik untuk menyelesaikan tugas di bawah keadaan yang berbeda. Anda juga dapat dengan tenang menangani berbagai masalah bersamaan yang Anda hadapi dalam kehidupan sehari -hari.