Kunci Pemblokiran versus Kunci Non-Pemblokiran

Saya berpikir di sini: Jika Anda memiliki 2 utas yang menjalankan operasi CEPAT yang perlu disinkronkan, bukankah pendekatan nonblocking lebih cepat/lebih baik daripada pendekatan pemblokiran/saklar konteks?

Yang saya maksud dengan non-pemblokiran adalah:

while(true) { if (checkAndGetTheLock()) rusak; }

Satu-satunya hal yang dapat saya pikirkan adalah kelaparan (dengan kehabisan CPU) jika Anda memiliki terlalu banyak utas yang berputar di sekitar kunci.

Bagaimana cara menyeimbangkan satu pendekatan dengan pendekatan lainnya?


person chrisapotek    schedule 27.02.2012    source sumber
comment
Berapa banyak operasi kunci yang akan Anda lakukan per inti CPU per detik?   -  person usr    schedule 27.02.2012
comment
AFAIK, JVM melakukan pengoptimalan ini untuk Anda jika tidak ada pertentangan pada kunci (yang seharusnya terjadi jika pengoperasiannya cepat)   -  person JB Nizet    schedule 27.02.2012
comment
@JB Nizet: Saya rasa Anda harus membuat keputusan itu sendiri dengan menggunakan sinkronisasi versus ReentrantLock.   -  person chrisapotek    schedule 27.02.2012


Jawaban (2)


Inilah yang Java Concurrency in Practice katakan tentang subjek ini:

JVM dapat menerapkan pemblokiran melalui spin-waiting (berulang kali mencoba mendapatkan kunci hingga berhasil) atau dengan menangguhkan thread yang diblokir melalui sistem operasi. Mana yang lebih efisien bergantung pada hubungan antara overhead pengalihan konteks dan waktu hingga kunci tersedia; spin-waiting lebih disukai untuk penantian singkat dan penangguhan lebih disukai untuk penantian lama. Beberapa JVM memilih di antara keduanya secara adaptif berdasarkan data pembuatan profil dari waktu tunggu yang lalu, namun sebagian besar hanya menangguhkan thread yang menunggu kunci.

Dan juga (yang, IMO, poin terpenting):

Jangan terlalu khawatir tentang biaya sinkronisasi yang tidak terbantahkan. Mekanisme dasarnya sudah cukup cepat, dan JVM dapat melakukan optimasi tambahan yang selanjutnya mengurangi atau menghilangkan biaya. Sebaliknya, fokuskan upaya pengoptimalan pada area di mana pertentangan kunci benar-benar terjadi.

person JB Nizet    schedule 27.02.2012
comment
Saya tidak akan percaya bahwa Beberapa JVM memilih di antara keduanya secara adaptif berdasarkan data profil waktu tunggu yang lalu, tetapi sebagian besar hanya menangguhkan utas yang menunggu kunci. Namun Anda tidak akan pernah tahu kemampuan JVM hotspot modern tersebut. Menurut saya sinkronisasi sedang memblokir dan ReentrantLock sedang sibuk menunggu. Tapi apakah mereka bisa berubah menjadi satu sama lain saat runtime, saya tidak yakin. - person chrisapotek; 27.02.2012
comment
Di mana Anda pernah membaca bahwa ReentrantLock sedang sibuk menunggu? Jika ya, hal ini akan membuat JVM bertekuk lutut karena penantian yang lama. Javadoc mengatakan: Kunci pengecualian timbal balik yang masuk kembali dengan perilaku dasar dan semantik yang sama dengan kunci monitor implisit yang diakses menggunakan metode dan pernyataan yang disinkronkan, tetapi dengan kemampuan yang diperluas. - person JB Nizet; 27.02.2012
comment
Saya bisa saja salah, tetapi dengan menjelajahi kode sumber saya pikir itu adalah pendekatannya: fuseyism.com/classpath/doc/java/util/concurrent/locks/ TIDAKOOOO! JVM TIDAK menggunakan ReentrantLock untuk hal-hal internalnya. - person chrisapotek; 27.02.2012
comment
@chrisapotek ReentrantLock dibuat menggunakan AbstrakQueuedSynchronizer sebagai mekanisme sinkronisasi. Dengan kata lain ReentrantLock menggunakan AbstrakQueuedSynchronizer untuk menangguhkan dan membangunkan thread. Namun seperti yang dicatat oleh JB Nizet, ReentrantLock benar-benar merupakan konstruksi pemblokiran - person John Vint; 28.02.2012
comment
Jadi jika saya ingin menggunakan kunci tunggu sibuk saya harus melakukannya sendiri menggunakan atom primitif, bukan? - person chrisapotek; 28.02.2012
comment
@chrisapotek Ya, Anda dapat menulis Mutex sederhana menggunakan AtomicBoolean. while(!flag.compareAndSet(false,true)); akan menjadi perolehan kunci putaran yang sibuk. - person John Vint; 29.02.2012

Satu-satunya cara untuk memastikannya adalah mengujinya. Dalam hal multithreading dan kinerja, Anda tidak dapat berasumsi.

person M Platvoet    schedule 27.02.2012
comment
@usr baiklah, mengapa Anda tidak memberi suara positif? Saya sangat tergoda untuk memberikan suara negatif dua kali, tetapi itu tidak adil bagi M Platvoet. - person Martin James; 27.02.2012
comment
@usr - dalam hal ini, saya akan menambahkan suara positif juga, karena itulah satu-satunya cara untuk memastikannya. Pengujian itu penting, tetapi sebelum pengembang mencapai tahap itu, ada beberapa desain yang pasti akan menghasilkan kinerja buruk, tidak perlu asumsi. Tidak menggunakannya adalah masalah pelatihan/pengalaman. - person Martin James; 27.02.2012