Dalam pemrograman multi-threaded, masalah yang paling kritis dan paling peduli harus menjadi masalah sinkronisasi, yang merupakan poin yang sulit dan inti.
Dari yang disinkronkan dan mudah berubah dari versi JDK yang paling awal, hingga antarmuka kunci di java.util.concurrent.locks Paket yang disediakan dalam JDK 1.5 (implementasi termasuk Readlock, Writelock, dan Reentrantlock), implementasi multi-threading juga secara bertahap matang.
Mekanisme apa yang digunakan untuk mengontrol sinkronisasi? Reaksi pertama adalah mengunci, yang seharusnya terpapar saat mempelajari sistem operasi dan database. Dalam program multi-threaded Java, ketika beberapa program bersaing untuk sumber daya yang sama, untuk mencegah korosi sumber daya, utas pertama yang mengakses sumber daya ditugaskan kunci objek, dan generasi selanjutnya perlu menunggu pelepasan kunci objek ini.
Ya, hal yang paling peduli tentang sinkronisasi utas Java adalah penggunaan sumber daya bersama.
Pertama -tama mari kita pahami beberapa sumber daya bersama dari utas mana yang tersedia.
Dari JVM, kita perlu mengoordinasikan data yang dibagikan berdasarkan utas:
1. Variabel instan yang disimpan di heap; 2. Variabel kelas disimpan di area metode.
Ketika mesin virtual Java memuat kelas, setiap objek atau kelas akan dikaitkan dengan monitor untuk melindungi variabel instance objek atau variabel kelas; Tentu saja, jika objek tidak memiliki variabel instance, atau kelas tidak memiliki variabel, monitor tidak akan memantau apa pun.
Untuk mencapai mutex monitor yang disebutkan di atas, mesin virtual mengaitkan kunci (juga disebut kunci yang tidak terlihat) untuk setiap objek atau kelas. Izinkan saya menjelaskan di sini bahwa kunci kelas juga diimplementasikan melalui kunci objek, karena ketika kelas dimuat, JVM akan membuat instance java.lang.class untuk setiap kelas; Jadi ketika kunci terhadap objek, objek kelas kelas ini terkunci.
Selain itu, utas dapat mengunci objek beberapa kali, yang sesuai dengan beberapa rilis; Ini adalah kalkulator kunci yang disediakan oleh JVM untuk setiap kunci objek. Kunci terakhir ditambahkan 1, dan minus 1 yang sesuai, dan ketika nilai kalkulator adalah 0, dilepaskan. Kunci objek ini digunakan oleh monitor di dalam JVM dan juga secara otomatis dihasilkan oleh JVM. Semua programmer tidak perlu menambahkannya sendiri.
Setelah memperkenalkan prinsip sinkronisasi Java, kita akan membahas topik dan pertama -tama berbicara tentang penggunaan sinkronisasi. Sinkronisasi lain akan diperkenalkan di bab -bab berikut.
Mari kita coba menjalankan contoh terlebih dahulu.
paket thread_test; / *** Uji program multithreaded yang memperluas implementasi kelas utas**/ kelas publik testThread memperluas thread {private int threadnum; testThread publik (int threadnum) {this.threadnum = threadnum; } @Override public disinkronkan void run () {for (int i = 0; i <1000; i ++) {System.out.println ("no." + Threadnum + ":" + i); }} public static void main (string [] args) melempar Exception {for (int i = 0; i <10; i ++) {testThread baru (i) .start (); Thread.sleep (1); }}}
Hasil Menjalankan:
No.0: 887 No.0: 888 No.0: 889 No.0: 890 No.0: 891 No.0: 892 No.0: 893 No.0: 894 No.7: 122 No.7: 123 No.7: 124
Di atas hanyalah sebuah klip, menjelaskan masalah.
Jika Anda berhati -hati, Anda akan menemukan bahwa No.0: 894 diikuti oleh No.7: 122, yang berarti tidak mulai dari 0 hingga 999.
Dikatakan bahwa disinkronkan dapat menerapkan metode sinkronisasi atau blok sinkronisasi, mengapa tidak dapat bekerja di sini?
Pertama -tama mari kita analisis mekanisme sinkronisasi. Sinkronisasi dicapai melalui penguncian. Jadi dalam contoh di atas, objek apa yang terkunci atau kelas apa yang terkunci? Ada dua variabel di dalamnya, satu adalah saya dan yang lainnya adalah threadnum; Saya internal dengan metode ini, dan Threadnum bersifat pribadi.
Mari kita pelajari tentang mekanisme lari yang disinkronkan:
Dalam program Java, ketika blok yang disinkronkan atau metode yang disinkronkan digunakan, area ini ditandai untuk pemantauan; Sementara ketika JVM menangani program, ketika suatu program memasuki area pemantauan, itu akan secara otomatis mengunci objek atau kelas.
Jadi dalam contoh di atas, apa yang terkunci setelah kata kunci yang disinkronkan digunakan?
Saat metode yang disinkronkan, kunci objek instan yang menyebut metode itu sendiri sebagai kunci objek. Dalam contoh ini, 10 utas memiliki objek kelas testthread mereka sendiri, sehingga kunci objek yang diperoleh juga merupakan kunci objek sendiri dan tidak ada hubungannya dengan utas lain.
Untuk mengimplementasikan penguncian metode, objek bersama harus dikunci.
Ubah contoh di atas dan kemudian lihat:
paket thread_test; / *** Uji program multithreaded yang memperluas implementasi kelas utas**/ kelas publik testThread memperluas thread {private int threadnum; bendera string pribadi; // tandai public testthread (int threadnum, string flag) {this.threadnum = threadnum; this.flag = bendera; } @Override public void run () {disinkronkan (flag) {for (int i = 0; i <1000; i ++) {System.out.println ("no." + Threadnum + ":" + i); }}} public static void main (string [] args) melempar Exception {string flag = new string ("flag"); untuk (int i = 0; i <10; i ++) {testThread baru (i, flag) .start (); Thread.sleep (1); }}}
Ini juga ditambahkan bendera bersama. Kemudian, bendera bendera disinkronkan melalui blok yang disinkronkan; Ini memenuhi persyaratan untuk mengunci objek bersama.
Ya, hasil berjalan telah terjadi.
Melalui blok yang disinkronkan, tentukan akuisisi kunci objek untuk mencapai sinkronisasi. Jadi, apakah ada metode lain yang dapat diimplementasikan melalui metode yang disinkronkan?
Menurut prinsip sinkronisasi: jika kunci objek bersama atau kunci kelas dapat diperoleh, sinkronisasi dapat dicapai. Jadi bisakah kita mencapainya dengan berbagi kunci kelas?
Ya, kita dapat menggunakan metode sinkronisasi statis. Menurut karakteristik metode statis, itu hanya memungkinkan objek kelas itu sendiri dipanggil, dan tidak dapat dipanggil dengan instantiasi objek kelas. Kemudian jika Anda mendapatkan kunci dari metode statis ini, Anda akan mendapatkan kunci kelas, dan kunci kelas ini adalah semua kunci kelas testthread, dan tujuan mendapatkan kunci kelas bersama tercapai.
Kode implementasi adalah sebagai berikut:
paket thread_test; / ** * Uji program multi-threaded yang memperluas implementasi kelas utas * * @Author memungut * @createTime 7 Des 2011 9:37:25 AM * */ kelas publik TestThread memperluas thread {private int threadnum; testThread publik (int threadnum) {this.threadnum = threadnum; } public static static void statictest (int threadnum) {for (int i = 0; i <1000; i ++) {System.out.println ("no." + threadnum + ":" + i); }} public static void main (string [] args) melempar Exception {for (int i = 0; i <10; i ++) {testThread baru (i) .start (); Thread.sleep (1); }} @Override public void run () {statictest (threadnum); }} Hasil lari dihilangkan, sama seperti pada contoh kedua.
Konten di atas terutama menjelaskan dua masalah: blok sinkronisasi dan metode sinkronisasi.
1. Blok yang disinkronkan: Kunci objek yang diperoleh adalah kunci objek bendera dalam sinkronisasi (bendera).
2. Metode Sinkronisasi: Objek kelas yang dimiliki metode, dan kunci objek kelas.
Metode sinkronisasi statis pasti akan disinkronkan karena beberapa utas akan dibagikan.
Alih -alih metode sinkronisasi statis, mereka hanya akan disinkronkan dalam mode singleton.