Adakah yang bisa memberi tahu saya keuntungan metode tersinkronisasi dari blok tersinkronisasi dengan contoh?
401
Adakah yang bisa memberi tahu saya keuntungan metode tersinkronisasi dari blok tersinkronisasi dengan contoh?
Jawaban:
Tidak ada keuntungan jelas menggunakan metode tersinkronisasi di atas blok.
Mungkin satu-satunya (tapi saya tidak akan menyebutnya keuntungan) adalah Anda tidak perlu memasukkan referensi objek
this
.Metode:
Blok:
Lihat? Tidak ada keuntungan sama sekali.
Blok memang memiliki keunggulan dibandingkan metode, sebagian besar dalam fleksibilitas karena Anda dapat menggunakan objek lain sebagai kunci sedangkan sinkronisasi metode akan mengunci seluruh objek.
Membandingkan:
vs.
Juga jika metode ini bertambah, Anda masih dapat memisahkan bagian yang disinkronkan:
sumber
synchronized
blok diimplementasikan dengan menggunakan dua instruksi,monitorenter
danmonitorexit
, ditambah handler pengecualian yang menjamin bahwamonitorexit
disebut bahkan dalam kasus luar biasa. Itu semua disimpan saat menggunakansynchronized
metode.Satu-satunya perbedaan nyata adalah bahwa blok yang disinkronkan dapat memilih objek yang disinkronkan. Metode yang disinkronkan hanya dapat menggunakan
'this'
(atau instance Kelas yang sesuai untuk metode kelas yang disinkronkan). Misalnya, ini setara secara semantik:Yang terakhir ini lebih fleksibel karena dapat bersaing untuk mengunci terkait objek apa pun , sering kali variabel anggota. Ini juga lebih terperinci karena Anda bisa memiliki kode bersamaan mengeksekusi sebelum dan sesudah blok tetapi masih dalam metode. Tentu saja, Anda dapat dengan mudah menggunakan metode yang disinkronkan dengan refactoring kode konkuren menjadi metode terpisah yang tidak disinkronkan. Gunakan mana saja yang membuat kode lebih mudah dipahami.
sumber
Metode Tersinkronisasi
Pro:
Cons:
Blok yang disinkronkan
Pro:
Cons:
Secara pribadi saya lebih suka menggunakan metode yang disinkronkan dengan kelas yang difokuskan hanya untuk hal yang membutuhkan sinkronisasi. Kelas tersebut harus sekecil mungkin dan karenanya harus mudah untuk meninjau sinkronisasi. Orang lain tidak perlu peduli dengan sinkronisasi.
sumber
Perbedaan utama adalah bahwa jika Anda menggunakan blok yang disinkronkan Anda dapat mengunci pada objek selain ini yang memungkinkan untuk menjadi jauh lebih fleksibel.
Asumsikan Anda memiliki antrian pesan dan banyak produsen dan konsumen pesan. Kami tidak ingin produsen saling mengganggu, tetapi konsumen harus dapat mengambil pesan tanpa harus menunggu produsen. Jadi kami hanya membuat objek
Dan mulai sekarang setiap kali seorang produsen ingin menambahkan pesan baru, kami hanya menguncinya:
Jadi konsumen mungkin masih membaca, dan produsen akan dikunci.
sumber
Metode yang disinkronkan
Metode yang disinkronkan memiliki dua efek.
Pertama, ketika satu utas mengeksekusi metode yang disinkronkan untuk suatu objek, semua utas lain yang memanggil metode yang disinkronkan untuk blok objek yang sama (menunda eksekusi) sampai utas pertama selesai dengan objek.
Kedua, ketika metode yang disinkronkan keluar, itu secara otomatis membangun hubungan yang terjadi sebelum dengan setiap doa berikutnya dari metode yang disinkronkan untuk objek yang sama. Ini menjamin bahwa perubahan keadaan objek terlihat oleh semua utas.
Perhatikan bahwa konstruktor tidak dapat disinkronkan - menggunakan kata kunci yang disinkronkan dengan konstruktor adalah kesalahan sintaksis. Menyinkronkan konstruktor tidak masuk akal, karena hanya utas yang membuat objek harus memiliki akses ke sana ketika sedang dibangun.
Pernyataan Tersinkronisasi
Tidak seperti metode yang disinkronkan, pernyataan yang disinkronkan harus menentukan objek yang menyediakan kunci intrinsik: Paling sering saya menggunakan ini untuk menyinkronkan akses ke daftar atau peta tetapi saya tidak ingin memblokir akses ke semua metode objek.
T: Kunci dan Sinkronisasi Intrinsik Sinkronisasi dibangun di sekitar entitas internal yang dikenal sebagai kunci intrinsik atau kunci monitor. (Spesifikasi API sering merujuk ke entitas ini hanya sebagai "monitor.") Kunci intrinsik berperan dalam kedua aspek sinkronisasi: menegakkan akses eksklusif ke keadaan objek dan membangun hubungan sebelum terjadi yang penting untuk visibilitas.
Setiap objek memiliki kunci intrinsik yang terkait dengannya. Dengan konvensi, utas yang memerlukan akses eksklusif dan konsisten ke bidang objek harus memperoleh kunci intrinsik objek sebelum mengaksesnya, dan kemudian melepaskan kunci intrinsik ketika dilakukan dengan mereka. Sebuah thread dikatakan memiliki kunci intrinsik antara waktu kunci tersebut diperoleh dan melepaskan kunci tersebut. Selama utas memiliki kunci intrinsik, tidak ada utas lain yang bisa mendapatkan kunci yang sama. Utas lainnya akan memblokir ketika mencoba untuk mendapatkan kunci.
Periksa silang keluaran yang berbeda dengan metode yang disinkronkan, blokir dan tanpa sinkronisasi.
sumber
Catatan: metode dan blok tersinkronisasi statis berfungsi pada objek Class.
sumber
Ketika kompiler java mengubah kode sumber Anda menjadi kode byte, ia menangani metode yang disinkronkan dan blok yang disinkronkan sangat berbeda.
Ketika JVM mengeksekusi metode yang disinkronkan, thread yang mengeksekusi mengidentifikasi bahwa metode method_info metode memiliki set flag ACC_SYNCHRONIZED, kemudian secara otomatis memperoleh kunci objek, memanggil metode, dan melepaskan kunci. Jika pengecualian terjadi, utas secara otomatis melepaskan kunci.
Menyinkronkan blok metode, di sisi lain, memotong dukungan bawaan JVM untuk memperoleh kunci objek dan penanganan pengecualian dan mengharuskan fungsi dituliskan secara eksplisit dalam kode byte. Jika Anda membaca kode byte untuk metode dengan blok yang disinkronkan, Anda akan melihat lebih dari selusin operasi tambahan untuk mengelola fungsi ini.
Ini menunjukkan panggilan untuk menghasilkan metode yang disinkronkan dan blok yang disinkronkan:
The
synchronizedMethodGet()
Metode menghasilkan kode byte berikut:Dan inilah kode byte dari
synchronizedBlockGet()
metode ini:Salah satu perbedaan yang signifikan antara metode dan blok yang disinkronkan adalah bahwa, Blok yang disinkronkan umumnya mengurangi cakupan kunci. Karena ruang lingkup kunci berbanding terbalik dengan kinerja, selalu lebih baik untuk mengunci hanya bagian penting dari kode. Salah satu contoh terbaik menggunakan blok tersinkronisasi adalah penguncian ganda diperiksa dalam pola Singleton di mana alih-alih mengunci seluruh
getInstance()
metode, kami hanya mengunci bagian kode yang penting yang digunakan untuk membuat instance Singleton. Ini meningkatkan kinerja secara drastis karena penguncian hanya diperlukan satu atau dua kali.Saat menggunakan metode yang disinkronkan, Anda harus berhati-hati jika Anda mencampur metode tersinkronisasi statis dan non-statis.
sumber
monitorenter
danmonitorexit
sebelum menjalankan kode.Paling sering saya menggunakan ini untuk menyinkronkan akses ke daftar atau peta tetapi saya tidak ingin memblokir akses ke semua metode objek.
Dalam kode berikut satu utas memodifikasi daftar tidak akan memblokir menunggu utas yang mengubah peta. Jika metode disinkronkan pada objek maka setiap metode harus menunggu meskipun modifikasi yang mereka buat tidak akan konflik.
sumber
Dengan blok yang disinkronkan, Anda dapat memiliki beberapa sinkronisasi, sehingga banyak hal yang simultan tetapi tidak bertentangan dapat berlangsung secara bersamaan.
sumber
Metode yang disinkronkan dapat diperiksa menggunakan API refleksi. Ini berguna untuk menguji beberapa kontrak, seperti semua metode dalam model disinkronkan .
Cuplikan berikut mencetak semua metode Hashtable yang disinkronkan:
sumber
Catatan penting tentang penggunaan blok yang disinkronkan: hati-hati apa yang Anda gunakan sebagai objek kunci!
Cuplikan kode dari user2277816 di atas mengilustrasikan hal ini karena referensi ke string literal digunakan sebagai objek penguncian. Sadarilah bahwa string literal secara otomatis diinternir di Jawa dan Anda harus mulai melihat masalahnya: setiap bagian kode yang disinkronkan pada "kunci" literal, berbagi kunci yang sama! Ini dapat dengan mudah menyebabkan kebuntuan dengan potongan kode yang sama sekali tidak terkait.
Bukan hanya objek String yang perlu Anda perhatikan. Kotak primitif juga merupakan bahaya, karena proses otomatis dan metode valueOf dapat menggunakan kembali objek yang sama, tergantung pada nilainya.
Untuk informasi lebih lanjut, lihat: https://www.securecoding.cert.org/confluence/display/java/LCK01-J.+Do+not+synchronize+on+objects+that+may+be+reusedreused
sumber
Seringkali menggunakan kunci pada level metode terlalu kasar. Mengapa mengunci sepotong kode yang tidak mengakses sumber daya bersama dengan mengunci seluruh metode. Karena setiap objek memiliki kunci, Anda dapat membuat objek tiruan untuk menerapkan sinkronisasi level blok. Level blok lebih efisien karena tidak mengunci keseluruhan metode.
Berikut beberapa contohnya
Tingkat Metode
Tingkat Blok
[Sunting]
Untuk
Collection
sukaVector
danHashtable
mereka disinkronkan saatArrayList
atauHashMap
tidak dan Anda perlu mengatur kata kunci yang disinkronkan atau memanggil metode yang disinkronkan Koleksi:sumber
Satu-satunya perbedaan: blok tersinkronisasi memungkinkan penguncian granular tidak seperti metode yang disinkronkan
Pada dasarnya
synchronized
blok atau metode telah digunakan untuk menulis kode aman utas dengan menghindari kesalahan inkonsistensi memori.Pertanyaan ini sudah sangat lama dan banyak hal telah berubah selama 7 tahun terakhir. Konstruksi pemrograman baru telah diperkenalkan untuk keamanan utas.
Anda dapat mencapai keamanan utas dengan menggunakan API konkurensi canggih, bukan
synchronied
blok. Halaman dokumentasi ini menyediakan konstruksi pemrograman yang baik untuk mencapai keamanan utas.Lock Objects mendukung idiom pengunci yang menyederhanakan banyak aplikasi bersamaan.
Pelaksana menetapkan API tingkat tinggi untuk meluncurkan dan mengelola utas. Implementasi pelaksana yang disediakan oleh java.util.concurrent menyediakan manajemen kumpulan thread yang cocok untuk aplikasi skala besar.
Koleksi Bersamaan membuatnya lebih mudah untuk mengelola koleksi data yang besar, dan dapat sangat mengurangi kebutuhan untuk sinkronisasi.
Variabel Atom memiliki fitur yang meminimalkan sinkronisasi dan membantu menghindari kesalahan konsistensi memori.
ThreadLocalRandom (dalam JDK 7) menyediakan generasi nomor pseudorandom yang efisien dari berbagai utas.
Penggantian yang lebih baik untuk disinkronkan adalah ReentrantLock , yang menggunakan
Lock
APIContoh dengan kunci:
Mengacu pada java.util.concurrent dan java.util.concurrent.atomic paket juga untuk konstruksi pemrograman lainnya.
Lihat pertanyaan terkait ini juga:
Sinkronisasi vs Kunci
sumber
Metode yang disinkronkan digunakan untuk mengunci semua objek Blok yang disinkronkan digunakan untuk mengunci objek tertentu
sumber
Secara umum ini sebagian besar sama selain eksplisit tentang monitor objek yang digunakan vs objek implisit ini. Salah satu kelemahan dari metode yang disinkronkan yang saya pikir kadang-kadang diabaikan adalah bahwa dalam menggunakan referensi "ini" untuk menyinkronkan Anda membiarkan kemungkinan objek eksternal terkunci pada objek yang sama. Itu bisa menjadi bug yang sangat halus jika Anda menabraknya. Sinkronisasi pada Obyek eksplisit internal atau bidang lain yang ada dapat menghindari masalah ini, sepenuhnya merangkum sinkronisasi.
sumber
Seperti yang sudah dikatakan di sini, blok yang disinkronkan dapat menggunakan variabel yang ditentukan pengguna sebagai objek kunci, ketika fungsi yang disinkronkan hanya menggunakan "ini". Dan tentu saja Anda dapat memanipulasi dengan area fungsi Anda yang harus disinkronkan. Tetapi semua orang mengatakan bahwa tidak ada perbedaan antara fungsi yang disinkronkan dan blok yang mencakup seluruh fungsi menggunakan "ini" sebagai objek kunci. Itu tidak benar, perbedaannya adalah dalam kode byte yang akan dihasilkan dalam kedua situasi. Dalam hal penggunaan blok tersinkronisasi harus dialokasikan variabel lokal yang memegang referensi untuk "ini". Dan sebagai hasilnya kita akan memiliki ukuran yang sedikit lebih besar untuk fungsi (tidak relevan jika Anda hanya memiliki sedikit fungsi).
Penjelasan lebih rinci tentang perbedaan ini dapat Anda temukan di sini: http://www.artima.com/insidejvm/ed2/threadsynchP.html
sumber
Dalam hal metode yang disinkronkan, kunci akan diperoleh pada Obyek. Tetapi jika Anda pergi dengan blok yang disinkronkan Anda memiliki opsi untuk menentukan objek di mana kunci akan diperoleh.
Contoh:
sumber
Saya tahu ini adalah pertanyaan lama, tetapi dengan cepat saya membaca tanggapan di sini, saya tidak benar-benar melihat ada yang menyebutkan bahwa kadang-kadang
synchronized
metode mungkin kunci yang salah .Dari Java Concurrency In Practice (hal 72):
Kode di atas memiliki tampilan sebagai thread-safe. Namun, pada kenyataannya tidak. Dalam hal ini kunci diperoleh pada instance kelas. Namun, daftar dapat dimodifikasi oleh utas lain yang tidak menggunakan metode itu. Pendekatan yang benar adalah menggunakan
Kode di atas akan memblokir semua utas yang mencoba mengubah daftar dari memodifikasi daftar hingga blok yang disinkronkan selesai.
sumber
List
dapat menyebabkan masalah kinerja jika ada log kode yang tidak perlu disinkronkanSebagai masalah praktis, keuntungan dari metode yang disinkronkan dari blok yang disinkronkan adalah bahwa mereka lebih tahan terhadap idiot; karena Anda tidak dapat memilih objek sewenang-wenang untuk dikunci, Anda tidak dapat menyalahgunakan sintaksis metode yang disinkronkan untuk melakukan hal-hal bodoh seperti mengunci string literal atau mengunci konten bidang yang bisa berubah yang diganti dari bawah utas.
Di sisi lain, dengan metode yang disinkronkan Anda tidak dapat melindungi kunci agar tidak didapat oleh utas apa pun yang bisa mendapatkan referensi ke objek.
Jadi menggunakan sinkronisasi sebagai pengubah pada metode lebih baik dalam melindungi pekerja sapi Anda dari menyakiti diri mereka sendiri, sementara menggunakan blok tersinkronisasi dalam hubungannya dengan objek kunci pribadi akhir lebih baik melindungi kode Anda sendiri dari pekerja sapi.
sumber
Dari ringkasan spesifikasi Java: http://www.cs.cornell.edu/andru/javaspec/17.doc.html
Berdasarkan uraian ini, saya akan mengatakan sebagian besar jawaban sebelumnya benar, dan metode yang disinkronkan mungkin sangat berguna untuk metode statis, di mana Anda harus mencari cara untuk mendapatkan "objek Class yang mewakili kelas di mana metode itu didefinisikan. "
Sunting: Awalnya saya pikir ini adalah kutipan dari spesifikasi Java yang sebenarnya. Mengklarifikasi bahwa halaman ini hanyalah ringkasan / penjelasan dari spesifikasi
sumber
TLDR; Tidak menggunakan
synchronized
pengubah atausynchronized(this){...}
ekspresi tetapi disynchronized(myLock){...}
manamyLock
bidang contoh terakhir memegang objek pribadi.Perbedaan antara menggunakan
synchronized
pengubah pada deklarasi metode dansynchronized(..){ }
ekspresi dalam tubuh metode adalah ini:synchronized
pengubah ditentukan pada tanda tangan metode inisynchronized(this) { .... }
, danthis
objek sebagai kunci ketika dideklarasikan pada metode non-statis atau kelas penutup ketika dideklarasikan pada metode statis.synchronized(...){...}
ekspresi memungkinkan AndaNamun, menggunakan
synchronized
pengubah atausynchronized(...) {...}
denganthis
sebagai objek kunci (seperti dalamsynchronized(this) {...}
), memiliki kelemahan yang sama. Keduanya menggunakan instance itu sendiri sebagai objek kunci untuk disinkronkan. Hal ini berbahaya karena tidak hanya obyek itu sendiri tetapi setiap eksternal lainnya objek / kode yang memegang referensi ke objek yang juga dapat menggunakannya sebagai kunci sinkronisasi dengan efek samping yang berat (penurunan kinerja dan deadlock ).Oleh karena itu praktik terbaik adalah tidak menggunakan
synchronized
pengubah atausynchronized(...)
ekspresi dalam hubungannya denganthis
sebagai objek kunci tetapi objek kunci pribadi untuk objek ini. Sebagai contoh:Anda juga dapat menggunakan beberapa objek kunci tetapi perlu perhatian khusus untuk memastikan ini tidak menghasilkan kebuntuan saat digunakan bersarang.
sumber
Saya kira pertanyaan ini adalah tentang perbedaan antara Thread Safe Singleton dan inisialisasi Lazy dengan penguncian cek ganda . Saya selalu merujuk ke artikel ini ketika saya perlu menerapkan beberapa singleton spesifik.
Nah, ini adalah Singleton Safe Thread :
Ini adalah inisialisasi Malas dengan penguncian periksa ganda :
Silakan merujuk ke artikel ini untuk lebih jelasnya:
https://www.geeksforgeeks.org/java-singleton-design-pattern-practices-examples/
sumber
Sinkronisasi dengan utas. 1) JANGAN PERNAH menggunakan disinkronkan (ini) di utas itu tidak berfungsi. Sinkronisasi dengan (ini) menggunakan utas saat ini sebagai objek utas pengunci. Karena setiap utas tidak tergantung pada utas lainnya, tidak ada koordinasi sinkronisasi. 2) Pengujian kode menunjukkan bahwa pada Java 1.6 pada Mac metode sinkronisasi tidak berfungsi. 3) disinkronkan (lockObj) di mana lockObj adalah objek bersama dari semua utas yang disinkronkan akan berfungsi. 4) ReenterantLock.lock () dan .unlock () berfungsi. Lihat tutorial Java untuk ini.
Kode berikut menunjukkan poin-poin ini. Ini juga mengandung Vector thread-safe yang akan diganti untuk ArrayList, untuk menunjukkan bahwa banyak utas yang menambahkan ke Vector tidak kehilangan informasi apa pun, sedangkan yang sama dengan ArrayList dapat kehilangan informasi. 0) Kode saat ini menunjukkan hilangnya informasi karena kondisi balapan A) Komentari garis berlabel A saat ini, dan batalkan komentar pada garis A di atasnya, lalu jalankan, metode kehilangan data tetapi tidak seharusnya. B) Balikkan langkah A, tanda komentar B dan // blok akhir}. Kemudian jalankan untuk melihat hasil, tidak ada kehilangan data C) Komentar B, batalkan komentar C. Jalankan, lihat sinkronisasi pada (ini) kehilangan data, seperti yang diharapkan. Tidak punya waktu untuk menyelesaikan semua variasi, harap ini membantu. Jika sinkronisasi pada (ini), atau metode sinkronisasi berfungsi, sebutkan versi Java dan OS apa yang Anda uji. Terima kasih.
sumber