Artikel ini menjelaskan perbedaan antara sinkronisasi (kunci objek) dan statis disinkronkan (kunci kelas) di java. Bagikan untuk referensi Anda, sebagai berikut:
Perbedaan antara sinkronisasi yang disinkronkan dan statis
Dengan menganalisis analisis kedua penggunaan ini, kita dapat memahami konsep kunci di Java. Salah satunya adalah kunci instance (terkunci pada objek instan. Jika kelas adalah singleton, maka kunci juga memiliki konsep kunci global), dan yang lainnya adalah kunci global (kunci ditargetkan pada kelas. Tidak peduli berapa banyak objek contohnya, utas berbagi kunci). Kunci instan sesuai dengan kata kunci yang disinkronkan, sedangkan kunci kelas (kunci global) sesuai dengan statis yang disinkronkan (atau terkunci pada objek kelas atau classloader kelas).
Artikel berikut memberikan ringkasan yang baik:
1. Perbedaan antara disinkronkan yang disinkronkan dan statis
Kunci Sinkronisasi Instance saat ini (objek saat ini) dari kelas untuk mencegah utas lain mengakses semua blok yang disinkronkan dari instance kelas pada saat yang sama. Perhatikan bahwa ini adalah "instance saat ini dari kelas". Tidak ada kendala seperti itu pada dua contoh kelas yang berbeda.
Kemudian disinkronkan statis terjadi untuk mengontrol akses bersamaan dari semua contoh kelas, dan statis yang disinkronkan membatasi semua contoh kelas dalam multi-threads untuk mengakses blok kode yang sesuai dengan kelas dalam JVM pada saat yang sama. Bahkan, jika ada disinkronkan dalam metode atau blok kode di kelas, setelah menghasilkan instance kelas, instance juga akan memiliki blok pemantauan untuk mencegah utas dari mengakses blok perlindungan yang disinkronkan secara bersamaan dari instance. Sinkronisasi statis adalah blok pemantauan yang umum untuk semua contoh kelas. Ini adalah perbedaan antara mereka berdua. Dengan kata lain, disinkronkan setara dengan hal ini. Sintrum, sedangkan statis disinkronkan setara dengan sesuatu. (Ditangani nanti)
Seorang penulis Jepang, "pola desain multithreaded Java" Java Chenghao memiliki kolom seperti ini:
PULBIC CLASS SESUATU () {public disinkronkan void issynca () {} public disinkronkan void issyncb () {} public static static void csynca () {} public static void csyncb () {}} public static static void csyncb () {}Jadi, jika ada dua contoh x dan y dari kelas sesuatu, apa masalahnya ketika kelompok metode berikut diakses secara bersamaan oleh banyak utas?
Axissynca () dan x.issyncb ()
bxissynca () dan y.issynca ()
cxcsynca () dan y.csyncb ()
dxissynca () dan sesuatu.csynca ()
Di sini, jelas bahwa itu dapat dinilai:
A, semua adalah akses domain yang disinkronkan ke instance yang sama (x), dan karenanya tidak dapat diakses secara bersamaan. (Berbagai domain yang disinkronkan yang mengakses X dalam multithreads tidak dapat diakses secara bersamaan)
Jika x.issynca () diakses di beberapa utas, karena masih merupakan instance yang sama dan terkunci pada metode yang sama, tidak dapat diakses di beberapa utas secara bersamaan. (Domain tersinkronisasi yang sama yang mengakses x di multithreads tidak dapat diakses secara bersamaan)
B, adalah untuk contoh yang berbeda, sehingga dapat diakses pada saat yang sama (kunci objek tidak memiliki kendala kunci untuk contoh objek yang berbeda)
C, karena disinkronkan statis, contoh yang berbeda masih akan dibatasi, yang setara dengan sesuatu.
Jadi, bagaimana dengan D?, Jawaban dalam buku ini dapat diakses secara bersamaan. Alasan jawabannya adalah bahwa sinkronisasi adalah bahwa metode instan dan metode kelas yang disinkronkan berbeda dari kunci.
Analisis pribadi berarti bahwa disinkronkan yang disinkronkan dan statis setara dengan dua geng, yang masing -masing memiliki kendali sendiri, dan tidak ada kendala satu sama lain dan dapat diakses pada saat yang sama.
Misalnya:
testsynchronized kelas publik {public disinkronkan void test1 () {int i = 5; while (i--> 0) {System.out.println (thread.currentThread (). getName () + ":" + i); coba {thread.sleep (500); } catch (InterruptedException IE) {}}} public static static void test2 () {int i = 5; while (i--> 0) {System.out.println (thread.currentThread (). getName () + ":" + i); coba {thread.sleep (500); } catch (InterruptedException IE) {}}} public static void main (string [] args) {final testsynchronized myt2 = testsynchronized baru (); Thread test1 = utas baru (runnable baru () {public void run () {myt2.test1 ();}}, "test1"); Thread test2 = utas baru (runnable baru () {public void run () {testsynchronized.test2 ();}}, "test2"); test1.start (); test2.start (); // testRunnable tr = new testRunnable (); // thread test3 = utas baru (tr); // test3.start (); }}test1: 4 test2: 4 test1: 3 test2: 3 test2: 2 test1: 2 test2: 1 test1: 1 test1: 0 test2: 0
Kode di atas yang disinkronkan memodifikasi metode statis dan metode instan pada saat yang sama, tetapi hasil berjalan dilakukan secara bergantian, yang membuktikan bahwa kunci kelas dan kunci objek adalah dua kunci yang berbeda, mengendalikan daerah yang berbeda, dan mereka tidak saling mengganggu. Demikian pula, sementara utas mendapatkan kunci objek, mereka juga dapat memperoleh jenis kunci ini, yaitu, mereka mendapatkan dua kunci secara bersamaan, yang diizinkan.
Kesimpulan:
A: Statis yang disinkronkan adalah ruang lingkup kelas tertentu. Sinkronisasi statis csync {} mencegah beberapa instance di beberapa utas dari mengakses metode statis yang disinkronkan di kelas ini pada saat yang sama. Ini bekerja pada semua instance objek kelas.
B: Sinkronisasi adalah ruang lingkup sebuah instance. Sinkronisasi ISSYNC () {} mencegah instance ini mengakses metode yang disinkronkan dari kelas ini secara bersamaan.
Bahkan, sangat mudah untuk diringkas.
2. Perbedaan antara metode yang disinkronkan dan kode yang disinkronkan dengan cepat
Tidak ada perbedaan antara metode yang disinkronkan () {} dan disinkronkan (ini) {}, tetapi metode yang disinkronkan () {} lebih mudah untuk pemahaman membaca, sementara disinkronkan (ini) {} dapat secara lebih akurat mengontrol konflik membatasi area akses, dan kadang -kadang berkinerja lebih efisien.
Perbandingan efisiensi antara dua metode:
1. Sinkronisasi blok, kodenya adalah sebagai berikut:
impor java.util.concurrent.countdownlatch; impor java.util.concurrent.executorservice; impor java.util.concurrent.Executors; testsynchronized kelas publik { / ** * @param args * / public static void main (string [] args) {ExecutorService Service = executors.newCachedThreadPool (); Final CountdownLatch CDorder = CountdownLatch baru (1); Final CountdownLatch CDASWER = NEW COUNTDOWNLATCH (3); final SynchonizedClass sc = new SynchonizedClass (); untuk (int i = 0; i <3; i ++) {runnable runnable = runnable baru () {public void run () {coba {cdorder.await (); sc.start (); CDASSWER.Countdown (); } catch (Exception e) {E.PrintStackTrace (); }}}; service.execute (runnable); } coba {thread.sleep ((long) (math.random ()*10000)); System.out.println ("Thread" + Thread.currentThread (). GetName () + "Publikasikan Perintah Eksekusi"); cdorder.countdown (); long beginTime = system.currentTimemillis (); System.out.println ("Thread" + Thread.currentThread (). GetName () + "Perintah telah dikirim, menunggu hasilnya"); CDASWER.AWAIT (); System.out.println ("Thread" + Thread.CurrentThread (). GetName ()) + "Semua hasil respons telah diterima, waktu yang diambil adalah:" + (System.CurrentTimeMillis ()-begintime)); } catch (Exception e) {E.PrintStackTrace (); } service.shutdown (); }} kelas SynchonizedClass {public void start () melempar InterruptedException {thread.sleep (100); // Jalankan logika lain untuk mengonsumsi waktu yang disinkronkan (this) {System.out.println ("Saya menjalankannya dengan 10 ms"); }}} Hasil operasi adalah sebagai berikut:
Thread Main Rilis Perintah Eksekusi, utas utama telah mengirim perintah, menunggu hasil yang saya jalankan dan menggunakan 10 ms
Saya sudah menjalankan menggunakan 10 ms
Saya sudah menjalankan menggunakan 10 ms
Thread Main telah menerima semua hasil respons, dan waktu yang dibutuhkan adalah: 110
Metode sinkronisasi, kodenya adalah sebagai berikut:
impor java.util.concurrent.countdownlatch; impor java.util.concurrent.executorservice; impor java.util.concurrent.Executors; testsynchronized kelas publik { / ** * @param args * / public static void main (string [] args) {ExecutorService Service = executors.newCachedThreadPool (); Final CountdownLatch CDorder = CountdownLatch baru (1); Final CountdownLatch CDASWER = NEW COUNTDOWNLATCH (3); final SynchonizedClass sc = new SynchonizedClass (); untuk (int i = 0; i <3; i ++) {runnable runnable = runnable baru () {public void run () {coba {cdorder.await (); sc.start (); CDASSWER.Countdown (); } catch (Exception e) {E.PrintStackTrace (); }}}; service.execute (runnable); } coba {thread.sleep ((long) (math.random ()*10000)); System.out.println ("Thread" + Thread.currentThread (). GetName () + "Publikasikan Perintah Eksekusi"); cdorder.countdown (); long beginTime = system.currentTimemillis (); System.out.println ("Thread" + Thread.currentThread (). GetName () + "Perintah telah dikirim, menunggu hasilnya"); CDASWER.AWAIT (); System.out.println ("Thread" + Thread.CurrentThread (). GetName ()) + "Semua hasil respons telah diterima, waktu yang diambil adalah:" + (System.CurrentTimeMillis ()-begintime)); } catch (Exception e) {E.PrintStackTrace (); } service.shutdown (); }} kelas SynchonizedClass {public disinkronkan void start () melempar InterruptedException {thread.sleep (100); // Jalankan waktu logika lainnya // disinkronkan (this) {system.out.println ("Saya menggunakan 10 ms"); //}}}Hasil operasi adalah sebagai berikut:
Thread Main Rilis Perintah Eksekusi, utas utama telah mengirim perintah, menunggu hasil yang saya jalankan dan menggunakan 10 ms
Saya sudah menjalankan menggunakan 10 ms
Saya sudah menjalankan menggunakan 10 ms
Thread Main telah menerima semua hasil respons, dan waktu yang dibutuhkan adalah: 332
Perbedaan antara keduanya adalah: 222ms.
Perbandingan menunjukkan bahwa blok kode sinkron lebih efisien daripada metode sinkronisasi.
Memori Tambahan:
1. Ada dua lingkup kata kunci yang disinkronkan:
1) Ini dalam instance objek. Amethod yang disinkronkan () {} dapat mencegah beberapa utas dari mengakses metode yang disinkronkan dari objek ini pada saat yang sama (jika suatu objek memiliki beberapa metode yang disinkronkan, selama satu utas mengakses salah satu metode yang disinkronkan, utas lain tidak dapat mengakses metode yang disinkronkan dalam objek pada saat yang sama). Pada saat ini, metode sinkronisasi dari berbagai contoh objek tidak terputus. Dengan kata lain, utas lain masih dapat mengakses metode yang disinkronkan dalam contoh objek lain dari kelas yang sama secara bersamaan;
2) Ini adalah ruang lingkup kelas tertentu. AstaticMethod statis yang disinkronkan {} mencegah objek instance yang berbeda (atau objek instance yang sama) di beberapa utas dari mengakses metode statis yang disinkronkan di kelas ini pada saat yang sama. Ini bekerja pada semua instance objek kelas.
2. Selain menggunakan kata kunci yang disinkronkan sebelum metode ini, kata kunci yang disinkronkan juga dapat digunakan dalam blok dalam metode ini, menunjukkan bahwa hanya akses yang saling eksklusif dilakukan pada sumber daya blok ini. Penggunaannya adalah: disinkronkan (ini) {/*blok*/} (atau disinkronkan (obj) {/*blok*/}), dan ruang lingkupnya adalah objek saat ini;
3. Kata kunci yang disinkronkan tidak dapat diwarisi. Artinya, metode kelas dasar yang disinkronkan f () {} tidak secara otomatis disinkronkan f () {} di kelas yang diwariskan, tetapi menjadi f () {}. Kelas warisan mengharuskan Anda untuk secara eksplisit menentukan bahwa salah satu metodenya disinkronkan;
Beberapa pemahaman tentang sinkronisasi (ini) (jelaskan kunci objek dengan baik, perhatikan kata kunci ini di dalamnya)
1. Ketika dua utas bersamaan mengakses blok kode sinkronisasi yang disinkronkan ini dalam objek objek yang sama, hanya satu utas yang dapat dieksekusi dalam satu waktu. Utas lain harus menunggu utas saat ini untuk menjalankan blok kode ini sebelum dapat menjalankan blok kode.
2. Namun, ketika satu utas mengakses blok kode sinkronisasi yang disinkronkan (ini) dari suatu objek, utas lain masih dapat mengakses blok kode sinkronisasi yang tidak disinkronkan (ini) di objek itu.
3. Sangat penting bahwa ketika utas mengakses blok kode sinkronisasi yang disinkronkan (ini) dari suatu objek, utas lain akan memblokir akses ke semua blok kode sinkronisasi yang disinkronkan (ini) dalam objek.
4. Contoh ketiga juga berlaku untuk blok kode sinkron lainnya. Artinya, ketika utas mengakses blok kode sinkronisasi yang disinkronkan (ini) dari suatu objek, ia memperoleh kunci objek objek ini. Akibatnya, utas lain akses ke semua bagian kode sinkron dari objek objek diblokir sementara.
5. Aturan di atas juga berlaku untuk kunci objek lainnya.
Tambahkan sepotong kode untuk memfasilitasi pengujian kata kunci yang disinkronkan (modifikasi sederhana)
testsynchronized kelas publik {public void test1 () {disinkronkan (this) {int i = 5; while (i--> 0) {System.out.println (thread.currentThread (). getName () + ":" + i); coba {thread.sleep (500); } catch (InterruptedException IE) {}}}} public disinkronkan void test2 () {int i = 5; while (i--> 0) {System.out.println (thread.currentThread (). getName () + ":" + i); coba {thread.sleep (500); } catch (InterruptedException IE) {}}} public disinkronkan void test3 () {int i = 5; while (i--> 0) {System.out.println (thread.currentThread (). getName () + ":" + i); coba {thread.sleep (500); } catch (InterruptedException IE) {}}} public static void main (string [] args) {final testsynchronized myt2 = testsynchronized baru (); testsynchronized final myt3 = testsynchronized baru (); Thread test1 = utas baru (runnable baru () {public void run () {myt2.test2 ();}}, "test1"); Thread test2 = utas baru (runnable baru () {public void run () {myt2.test3 ();}}, "test3"); test1.start () ;; test2.start (); }} Hasil Menjalankan:
test1: 4test1: 3test1: 2test1: 1test1: 0test3: 4test3: 3test3: 2test3: 1test3: 0
Di bawah ini kami fokus pada penggunaan Sychronized di Java, yang secara khusus: metode sinkronisasi dan kata kunci blok tersinkronisasi yang disinkronkan, yang mencakup dua penggunaan: metode yang disinkronkan dan blok yang disinkronkan.
1. Metode yang disinkronkan: Deklarasikan metode yang disinkronkan dengan menambahkan kata kunci yang disinkronkan ke deklarasi metode. menyukai:
public disinkronkan void accessVal (int newVal);
Metode yang disinkronkan mengontrol akses ke variabel anggota kelas: setiap instance kelas sesuai dengan kunci, dan setiap metode yang disinkronkan harus mendapatkan kunci instance kelas yang memanggil metode sebelum dapat dieksekusi. Kalau tidak, utas tempatnya diblokir. Setelah metode dieksekusi, itu akan secara eksklusif menempati kunci. Kunci tidak akan dirilis sampai kembali dari metode ini. Utas yang diblokir dapat memperoleh kunci dan masuk kembali ke negara bagian yang dapat dieksekusi. Mekanisme ini memastikan bahwa pada saat yang sama, untuk setiap contoh kelas, paling banyak dari semua fungsi anggota yang dinyatakan disinkronkan adalah dalam keadaan yang dapat dieksekusi (karena paling banyak orang dapat memperoleh kunci yang sesuai dengan instance kelas), sehingga secara efektif menghindari konflik akses variabel anggota kelas (selama semua metode yang memungkinkan untuk mengakses variabel anggota kelas dinyatakan disinkronisasi).
Di Java, tidak hanya contoh kelas, setiap kelas juga sesuai dengan kunci, sehingga kami dapat mendeklarasikan fungsi anggota statis kelas sebagai statis yang disinkronkan untuk mengontrol aksesnya ke variabel anggota statis kelas.
Kerugian dari metode yang disinkronkan: mendeklarasikan metode besar sebagaimana disinkronkan akan sangat mempengaruhi efisiensi. Biasanya, jika metode kelas utas berjalan () dinyatakan sebagai disinkronkan, karena telah berjalan sepanjang umur utas, itu akan menyebabkannya tidak pernah berhasil dalam metode yang disinkronkan dari kelas ini. Tentu saja kita dapat menyelesaikan masalah ini dengan menempatkan kode yang mengakses variabel anggota kelas ke dalam metode khusus, menyatakannya sebagai disinkronkan, dan menyebutnya dalam metode utama, tetapi Java memberi kita solusi yang lebih baik, yaitu, blok yang disinkronkan.
2. Blok Sinkronisasi: Deklarasikan blok yang disinkronkan melalui kata kunci yang disinkronkan. Sintaksnya adalah sebagai berikut:
Sinkronisasi (SyncObject) {// Kode yang memungkinkan kontrol akses} Blok yang disinkronkan adalah blok kode di mana kode harus mendapatkan kunci dari objek syncObject (seperti yang disebutkan sebelumnya, itu dapat berupa instance atau kelas kelas) sebelum dapat dieksekusi. Mekanisme spesifiknya sama seperti yang dijelaskan di atas. Karena dapat ditargetkan pada blok kode apa pun dan objek yang terkunci dapat ditentukan kapan saja, itu lebih fleksibel.
Melihat:
Saat menggunakan kata kunci yang disinkronkan, Anda harus menghindari menggunakan metode tidur atau hasil dalam metode yang disinkronkan atau blok yang disinkronkan sebanyak mungkin, karena blok program yang disinkronkan menempati kunci objek, jadi jika Anda beristirahat, utas lain hanya dapat dieksekusi sambil menunggu Anda untuk bangun dan menyelesaikan pelaksanaan. Tidak hanya mempengaruhi efisiensi secara serius, tetapi juga tidak logis.
Demikian pula, tidak masuk akal untuk memanggil metode Yeild di blok program sinkron untuk menyerahkan sumber daya CPU, karena Anda menempati kunci dan utas mutex lainnya masih tidak dapat mengakses blok program sinkron. Tentu saja, utas yang tidak terkait dengan blok program sinkron dapat memperoleh lebih banyak waktu eksekusi.
Di atas adalah semua konten artikel ini. Saya berharap ini akan membantu untuk pembelajaran semua orang dan saya harap semua orang akan lebih mendukung wulin.com.