Artikel ini membawa anda pengetahuan yang berkaitan tentang java, yang terutamanya memperkenalkan kandungan berkaitan tentang kunci, termasuk kunci optimistik, kunci pesimis, kunci eksklusif, kunci kongsi, dll., seperti berikut Mari kita lihat, Saya harap ia akan membantu semua orang.
Pembelajaran yang disyorkan: "tutorial video java"
悲观锁
Dalam bahasa Java,
danialah kunci pesimis biasa, begitu juga beberapa kelas kontena yang menggunakan kata kunci yang disegerakkan, seperti
Aplikasi penguncian pesimis. Kunci Optimissynchronized
ReentrantLock
HashTable
Sepadan dengan orang yang optimistik dalam kehidupan sentiasa berfikir tentang perkara yang menuju ke arah yang baik.
Untuk memberi contoh dalam kehidupan, andaikan hanya ada satu lubang di dalam tandas Optimistic Lock berfikir: Tidak ramai orang di hutan belantara ini, dan tiada siapa yang akan merampas lubang saya , kunci je, buang masa, lebih baik jangan kunci. Anda lihat, kunci optimis dilahirkan optimistik! Kembali dalam dunia kod, penguncian optimistik tidak akan dikunci semasa mengemas kini data, ia akan menentukan sama ada urutan lain akan mengemas kini data dalam tempoh ini.
乐观锁
Penguncian optimis boleh dilaksanakan menggunakan
dan. Dalam bahasa Java, kelas atom di bawah pakej
dilaksanakan menggunakan penguncian optimistik CAS. Senario penggunaan dua kunci版本号机制
CAS算法
Tiada kelebihan atau kekurangan antara kunci pesimis dan kunci optimis, dan mereka mempunyai senario sendiri untuk disesuaikan. java.util.concurrent.atomic
Jika senario dengan lebih banyak penulisan dan kurang bacaan, iaitu konflik adalah serius dan persaingan antara utas dirangsang, menggunakan kunci optimistik akan menyebabkan utas sentiasa mencuba semula, yang mungkin juga mengurangkan prestasi dalam senario ini , gunakan kunci pesimis Ia lebih sesuai.
Kunci eksklusif dan kunci kongsiKunci eksklusif
Kelas pelaksanaan Lock dalam pakej
dan 独占锁
dalam JDK ialah kunci eksklusif.
Kunci dikongsi
synchronized
java.util.concurrent(JUC)
bermakna kunci boleh dipegang oleh berbilang benang. Jika urutan menambahkan kunci kongsi pada data, urutan lain hanya boleh menambah kunci kongsi pada data dan tidak boleh menambah kunci eksklusif. Benang yang memperoleh kunci kongsi hanya boleh membaca data dan tidak boleh mengubah suai data.
Dalam JDK,
ialah kunci kongsi. 共享锁
ReentrantReadWriteLock
Kunci mutex Hanya satu utas boleh memiliki kunci mutex pada satu masa dan utas lain hanya boleh menunggu.
互斥锁
ialah pelaksanaan khusus kunci kongsi. Kunci baca-tulis mengurus satu set kunci, satu kunci baca sahaja dan satu lagi kunci tulis.
Kunci baca boleh dipegang oleh berbilang benang pada masa yang sama apabila tiada kunci tulis dan kunci tulis adalah eksklusif. Keutamaan kunci tulis adalah lebih tinggi daripada kunci baca Urutan yang memperoleh kunci baca mesti dapat melihat kandungan yang dikemas kini oleh kunci tulis yang dikeluarkan sebelum ini.
Kunci baca-tulis mempunyai tahap konkurensi yang lebih tinggi daripada kunci mutex Hanya terdapat satu utas tulisan pada satu masa, tetapi beberapa utas boleh membaca serentak pada masa yang sama.
mentakrifkan antara muka kunci baca-tulis dalam JDK: ReadWriteLock
public interface ReadWriteLock { /** * 获取读锁 */ Lock readLock(); /** * 获取写锁 */ Lock writeLock(); }
ReentrantReadWriteLock
melaksanakan antara muka ReadWriteLock
, khususnya The pelaksanaan tidak akan dikembangkan di sini, dan analisis kod sumber akan mendalam kemudian.
Kunci saksama
公平锁
bermakna berbilang utas memperoleh kunci mengikut susunan ia memohon kunci, di sini Sama seperti beratur untuk membeli tiket, mereka yang datang dahulu membeli, dan mereka yang datang kemudian menunggu dalam barisan di penghujung.
Di java, kunci adil boleh dimulakan melalui pembina
/** * 创建一个可重入锁,true 表示公平锁,false 表示非公平锁。默认非公平锁 */ Lock lock = new ReentrantLock(true);
Kunci tidak adil
非公平锁
bermaksud bahawa urutan berbilang benang memperoleh kunci tidak mengikut urutan yang digunakan untuk kunci. Kemungkinan benang yang digunakan kemudian memperoleh kunci sebelum benang yang digunakan terlebih dahulu, ini mungkin menyebabkan keutamaan membalik atau kebuluran Status (benang tidak pernah mendapat kunci).
Kata kunci yang disegerakkan dalam java ialah kunci yang tidak adil, dan ReentrantLock juga merupakan kunci yang tidak adil secara lalai.
/** * 创建一个可重入锁,true 表示公平锁,false 表示非公平锁。默认非公平锁 */ Lock lock = new ReentrantLock(false);
可重入锁
juga dipanggil 递归锁
, yang bermaksud benang yang sama memperoleh kunci dalam kaedah luar dan akan memperolehnya secara automatik apabila memasuki kaedah dalam Kunci.
Untuk Java ReentrantLock, namanya boleh memberitahu bahawa ia adalah kunci reentrant. Untuk Disegerakkan, ia juga merupakan kunci masuk semula.
Ketuk papan hitam: Satu faedah kunci masuk semula ialah kebuntuan boleh dielakkan pada tahap tertentu.
Ambil disegerakkan sebagai contoh Lihat kod berikut:
public synchronized void mehtodA() throws Exception{ // Do some magic tings mehtodB(); } public synchronized void mehtodB() throws Exception{ // Do some magic tings }
Dalam kod di atas, methodA memanggil methodB Jika thread memanggil methodA dan telah memperoleh kunci, maka tidak perlu memanggil kaedahB. Kunci diperoleh semula. Ini adalah ciri kunci masuk semula. Jika ia bukan kunci masuk semula, mehtodB mungkin tidak dilaksanakan oleh urutan semasa, yang boleh menyebabkan kebuntuan.
自旋锁
bermakna benang tidak digantung secara langsung apabila kunci tidak diperolehi, tetapi melaksanakan gelung sibuk ini adalah apa yang dipanggil putaran.
Tujuan kunci putaran adalah untuk mengurangkan peluang benang digantung, kerana penggantungan benang dan bangun tidur juga merupakan operasi yang memakan sumber.
Jika kunci diduduki oleh benang lain untuk masa yang lama, benang semasa masih akan digantung walaupun selepas berputar, dan gelung sibuk akan menjadi pembaziran sumber sistem, yang sebenarnya akan mengurangkan prestasi keseluruhan. Oleh itu, kunci putaran tidak sesuai untuk situasi konkurensi di mana kunci mengambil masa yang lama.
Di Java, kelas AtomicInteger
mempunyai operasi putaran Mari kita lihat kod:
public final int getAndAddInt(Object o, long offset, int delta) { int v; do { v = getIntVolatile(o, offset); } while (!compareAndSwapInt(o, offset, v, v + delta)); return v; }
Jika operasi CAS gagal, ia akan terus menggelung untuk mendapatkan arus. nilai dan kemudian cuba lagi.
Selain itu, kunci putaran adaptif juga perlu difahami.
Putaran suai telah diperkenalkan dalam JDK1.6 Ini adalah lebih pintar Masa putaran tidak lagi ditentukan oleh masa putaran sebelumnya pada kunci yang sama dan status pemilik kunci . Jika mesin maya berpendapat bahawa putaran ini berkemungkinan besar untuk berjaya lagi, ia akan mengambil lebih banyak masa Jika putaran jarang berjaya, ia mungkin secara langsung meninggalkan proses putaran pada masa hadapan untuk mengelakkan pembaziran sumber pemproses.
分段锁
ialah reka bentuk kunci, bukan kunci khusus.
Tujuan reka bentuk kunci bersegmen adalah untuk memperhalusi lagi butiran kunci Apabila operasi tidak perlu mengemas kini keseluruhan tatasusunan, hanya satu item dalam tatasusunan boleh dikunci.
Dalam bahasa Java, CurrentHashMap menggunakan kunci segmentasi di lapisan bawah Menggunakan Segmen, ia boleh digunakan secara serentak.
JDK1.6 Untuk meningkatkan prestasi dan mengurangkan penggunaan yang disebabkan oleh memperoleh dan melepaskan kunci, JDK1.6 memperkenalkan Terdapat 4 keadaan kunci: 无锁
, 偏向锁
, 轻量级锁
dan 重量级锁
, yang akan meningkat secara beransur-ansur disebabkan persaingan berbilang benang, tetapi tidak boleh diturunkan taraf.
Tiada kunci
无锁
Status sebenarnya ialah kunci optimistik yang dinyatakan di atas, yang tidak akan diterangkan di sini.
偏向锁
Java偏向锁(Biased Locking)是指它会偏向于第一个访问锁的线程,如果在运行过程中,只有一个线程访问加锁的资源,不存在多线程竞争的情况,那么线程是不需要重复获取锁的,这种情况下,就会给线程加一个偏向锁。
偏向锁的实现是通过控制对象Mark Word
的标志位来实现的,如果当前是可偏向状态
,需要进一步判断对象头存储的线程 ID 是否与当前线程 ID 一致,如果一致直接进入。
轻量级锁
当线程竞争变得比较激烈时,偏向锁就会升级为轻量级锁
,轻量级锁认为虽然竞争是存在的,但是理想情况下竞争的程度很低,通过自旋方式
等待上一个线程释放锁。
重量级锁
如果线程并发进一步加剧,线程的自旋超过了一定次数,或者一个线程持有锁,一个线程在自旋,又来了第三个线程访问时(反正就是竞争继续加大了),轻量级锁就会膨胀为重量级锁
,重量级锁会使除了此时拥有锁的线程以外的线程都阻塞。
升级到重量级锁其实就是互斥锁了,一个线程拿到锁,其余线程都会处于阻塞等待状态。
在 Java 中,synchronized 关键字内部实现原理就是锁升级的过程:无锁 --> 偏向锁 --> 轻量级锁 --> 重量级锁。这一过程在后续讲解 synchronized 关键字的原理时会详细介绍。
锁粗化
锁粗化
就是将多个同步块的数量减少,并将单个同步块的作用范围扩大,本质上就是将多次上锁、解锁的请求合并为一次同步请求。
举个例子,一个循环体中有一个代码同步块,每次循环都会执行加锁解锁操作。
private static final Object LOCK = new Object(); for(int i = 0;i <p>经过<code>锁粗化</code>后就变成下面这个样子了:</p><pre class="brush:php;toolbar:false"> synchronized(LOCK){ for(int i = 0;i <p><strong>锁消除</strong></p><p><code>锁消除</code>是指虚拟机编译器在运行时检测到了共享数据没有竞争的锁,从而将这些锁进行消除。</p><p>举个例子让大家更好理解。</p><pre class="brush:php;toolbar:false">public String test(String s1, String s2){ StringBuffer stringBuffer = new StringBuffer(); stringBuffer.append(s1); stringBuffer.append(s2); return stringBuffer.toString(); }
上面代码中有一个 test 方法,主要作用是将字符串 s1 和字符串 s2 串联起来。
test 方法中三个变量s1, s2, stringBuffer, 它们都是局部变量,局部变量是在栈上的,栈是线程私有的,所以就算有多个线程访问 test 方法也是线程安全的。
我们都知道 StringBuffer 是线程安全的类,append 方法是同步方法,但是 test 方法本来就是线程安全的,为了提升效率,虚拟机帮我们消除了这些同步锁,这个过程就被称为锁消除
。
StringBuffer.class // append 是同步方法 public synchronized StringBuffer append(String str) { toStringCache = null; super.append(str); return this; }
Java 并发编程的知识非常多,同时也是 Java 面试的高频考点,面试官必问的,需要学习 Java 并发编程其他知识的小伙伴可以去下载『阿里师兄总结的Java知识笔记 总共 283 页,超级详细』。
前面讲了 Java 语言中各种各种的锁,最后再通过六个问题统一总结一下:
推荐学习:《java视频教程》
Atas ialah kandungan terperinci Penjelasan terperinci dengan gambar dan teks! Ringkasan kunci dalam java. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!