Di JAVA, kata kunci yang disinkronkan dapat digunakan untuk kontrol sinkronisasi utas untuk mencapai akses berurutan ke sumber daya utama, dan menghindari ketidakkonsistenan data yang disebabkan oleh eksekusi bersamaan multi-threaded. Prinsip sinkronisasi adalah monitor objek (kunci). Hanya utas yang memperoleh monitor yang dapat terus mengeksekusi, jika tidak, utas akan menunggu untuk memperoleh monitor. Setiap objek atau kelas di Java memiliki kunci yang terkait dengannya. Untuk suatu objek, ia memantau variabel instance dari objek ini. Untuk kelas, ia memantau variabel kelas (kelas itu sendiri adalah objek kelas kelas, sehingga kunci yang terkait dengan kelas juga merupakan kunci objek). Ada dua cara untuk menggunakan kata kunci yang disinkronkan: metode yang disinkronkan dan blok yang disinkronkan. Kedua area pemantauan dikaitkan dengan objek yang diperkenalkan. Ketika mencapai area pemantauan ini, JVM akan mengunci objek referensi, dan ketika pergi, kunci pada objek referensi akan dilepaskan (JVM akan melepaskan kunci ketika ada keluar pengecualian). Kunci objek adalah mekanisme internal JVM. Anda hanya perlu menulis metode sinkronisasi atau blok sinkronisasi. Saat mengoperasikan area pemantauan, JVM akan secara otomatis memperoleh atau melepaskan kunci.
Contoh 1
Mari kita lihat contoh pertama. Di Java, hanya ada satu area kritis dari objek yang sama yang diizinkan diakses pada saat yang sama (semua metode sinkronisasi non-statis):
Paket Concurrency; Public Class Main8 {public static void main (string [] args) {akun akun = akun baru (); Account.setBalance (1000); Perusahaan Perusahaan = Perusahaan Baru (Akun); Utas perusahaanThread = utas baru (perusahaan); Bank bank = bank baru (akun); Thread bankthread = utas baru (bank); System.out.printf ("Akun: Saldo Awal: %f/n", Account.getalance ()); companyThread.start (); bankthread.start (); Coba {// gabungan () Metode menunggu kedua utas ini untuk menyelesaikan perusahaanThread.join (); bankthread.join (); System.out.printf ("Akun: Saldo Akhir: %f/n", Account.getBalance ()); } catch (InterruptedException e) {E.PrintStackTrace (); }}} /*Akun*/Kelas Akun {Private Double Balance; /*Tambahkan data yang masuk ke keseimbangan*/ addamount void yang disinkronkan publik (jumlah ganda) {double tmp = balance; coba {thread.sleep (10); } catch (InterruptedException e) {E.PrintStackTrace (); } tmp += jumlah; saldo = tmp; } /*Mengurangi data yang masuk dari saldo keseimbangan* / public disinkronkan void SubtractAnt (jumlah ganda) {double tmp = balance; coba {thread.sleep (10); } catch (InterruptedException e) {E.PrintStackTrace (); } tmp -= jumlah; saldo = tmp; } public double getBalance () {return balance; } public void setBalance (balance ganda) {this.balance = balance; }} /*Bank*/kelas bank mengimplementasikan Runnable {Private Account Account; bank umum (akun akun) {this.account = akun; } @Override public void run () {for (int i = 0; i <100; i ++) {Account.subtractamount (1000); }}} /*Perusahaan*/Kelas Perusahaan mengimplementasikan Runnable {Private Account Account; perusahaan publik (akun akun) {this.account = akun; } @Override public void run () {for (int i = 0; i <100; i ++) {Account.Addamount (1000); }}}Anda telah mengembangkan aplikasi simulasi untuk rekening bank yang dapat menambah dan mengurangi saldo. Program ini mengisi ulang akun dengan memanggil metode addamount () 100 kali, menyetor 1.000 setiap kali; kemudian mengurangi saldo akun dengan menghubungi metode Subtractamount () 100 kali, mengurangi 1.000 setiap kali; Kami berharap saldo akhir akun sama dengan saldo awal, dan kami mengimplementasikannya melalui kata kunci yang disinkronkan.
Jika Anda ingin melihat masalah akses bersamaan dari data bersama, Anda hanya perlu menghapus kata kunci yang disinkronkan di Deklarasi Metode Addamount () dan Subtractamount (). Tanpa kata kunci yang disinkronkan, nilai saldo cetak tidak konsisten. Jika Anda menjalankan program ini beberapa kali, Anda akan mendapatkan hasil yang berbeda. Karena JVM tidak menjamin urutan eksekusi utas, setiap kali berjalan, utas akan membaca dan memodifikasi saldo akun dalam pesanan yang berbeda, menghasilkan hasil akhir yang berbeda.
Metode objek dinyatakan menggunakan kata kunci yang disinkronkan dan hanya dapat diakses oleh satu utas. Jika Thread A mengeksekusi metode sinkronisasi sinkronisasi SyncMethoda (), Thread B ingin menjalankan metode sinkronisasi lain SyncMethodB () dari objek ini, Thread B akan diblokir sampai utas A menyelesaikan akses. Tetapi jika Thread B mengakses objek yang berbeda dari kelas yang sama, tidak ada utas yang akan diblokir.
Contoh 2
Tunjukkan masalah bahwa metode sinkronisasi statis dan metode sinkronisasi non-statis pada objek yang sama dapat diakses oleh beberapa utas secara bersamaan. Verifikasi.
Paket Concurrency; Public Class Main8 {public static void main (string [] args) {akun akun = akun baru (); Account.setBalance (1000); Perusahaan Perusahaan = Perusahaan Baru (Akun); Utas perusahaanThread = utas baru (perusahaan); Bank bank = bank baru (akun); Thread bankthread = utas baru (bank); System.out.printf ("Akun: Saldo Awal: %f/n", Account.getalance ()); companyThread.start (); bankthread.start (); Coba {// gabungan () Metode menunggu kedua utas ini untuk menyelesaikan perusahaanThread.join (); bankthread.join (); System.out.printf ("Akun: Saldo Akhir: %f/n", Account.getBalance ()); } catch (InterruptedException e) {E.PrintStackTrace (); }}} /*Akun*/Kelas Akun {/*Ubah ke variabel statis di sini*/Saldo ganda statis pribadi = 0; /*Tambahkan data yang masuk ke saldo saldo, perhatikan bahwa itu dimodifikasi dengan statis*/ public static void addamount (jumlah ganda) {double tmp = balance; coba {thread.sleep (10); } catch (InterruptedException e) {E.PrintStackTrace (); } tmp += jumlah; saldo = tmp; } /*Mengurangi data yang masuk dari saldo keseimbangan* / public yang disinkronkan void subtractAnt (jumlah ganda) {double tmp = balance; coba {thread.sleep (10); } catch (InterruptedException e) {E.PrintStackTrace (); } tmp -= jumlah; saldo = tmp; } public double getBalance () {return balance; } public void setBalance (balance ganda) {this.balance = balance; }} /*Bank*/kelas bank mengimplementasikan Runnable {Private Account Account; bank umum (akun akun) {this.account = akun; } @Override public void run () {for (int i = 0; i <100; i ++) {Account.subtractamount (1000); }}} /*Perusahaan*/Kelas Perusahaan mengimplementasikan Runnable {Private Account Account; perusahaan publik (akun akun) {this.account = akun; } @Override public void run () {for (int i = 0; i <100; i ++) {Account.Addamount (1000); }}}Saya baru saja menambahkan kata kunci statis untuk memodifikasi saldo pada contoh sebelumnya, dan metode addamount () juga dapat memodifikasi kata kunci statis. Anda dapat menguji hasil eksekusi sendiri, dan setiap eksekusi akan memiliki hasil yang berbeda!
Beberapa ringkasan: