Java中的自旋鎖與阻塞鎖詳解
自旋鎖
阻塞或者喚醒一個(gè)Java線程需要操作系統(tǒng)切換CPU 狀態(tài)來(lái)完成,這種狀態(tài)轉(zhuǎn)換 需要耗費(fèi)處理器時(shí)間 如果同步代碼塊到代碼過(guò)于簡(jiǎn)單,狀態(tài)轉(zhuǎn)換到時(shí)間有kennel比用戶執(zhí)行代碼到時(shí)間還長(zhǎng) 在許多場(chǎng)景下,同步資源到鎖定時(shí)間短,為了這小段時(shí)間切換線程,線程的掛起和恢復(fù)可能會(huì)讓系統(tǒng)得不償失,
這里是為了當(dāng)前線程“ 稍等一下”, 我們需要讓當(dāng)前線程進(jìn)行自旋 ,如果自旋完成后前面鎖定同步資源的線程以及釋放了鎖,那么當(dāng)前線程就沒(méi)必要阻塞,而是直接獲取同步資源,從而避免線程的開(kāi)銷(xiāo) 阻塞鎖和自旋鎖相反,阻塞鎖如果沒(méi)有拿到鎖,就會(huì)直接阻塞,知道被喚醒
阻塞鎖
阻塞鎖是指當(dāng)線程嘗試獲取鎖失敗時(shí),線程進(jìn)入阻塞狀態(tài),直到接收信號(hào)后被喚醒.(線程的狀態(tài)包括新建、就緒、運(yùn)行、阻塞及死亡)在JAVA中,能夠喚醒阻塞線程的操作包括Object.notify, Object.notifyAll, Condition.signal, LockSupport.unpark(JUC中引入)
原理和源碼分析
在 jdk 1.5 及以上并發(fā)框架 Java.util.concurrent 的 atomic 下 都是自旋鎖實(shí)現(xiàn)的
AtomicInteger 的實(shí)現(xiàn) :自旋鎖實(shí)現(xiàn)原理是CAS AtomicInteger 中是調(diào)用底層unsafe 進(jìn)行自增操作的源碼中的 do-while 循環(huán)就是一個(gè)自旋操作,如果修改過(guò)程中一踏線程競(jìng)爭(zhēng)導(dǎo)致修改失敗,就在while 死循環(huán),直至成功
package com.dimple.test;
/**
* 本實(shí)例演示下線程的自旋鎖的實(shí)現(xiàn)
*/
public class SpinLockDemo {
private static AtomicReference<Thread> atomicReference=new AtomicReference<>();
public void lock(){
Thread thread=Thread.currentThread();
while(!atomicReference.compareAndSet(null,thread)){
System.out.println(thread.getName()+"自旋鎖獲取失敗,重新獲取中");
}
}
public void unlock(){
Thread thread=Thread.currentThread();
atomicReference.compareAndSet(thread,null);
}
public static void main(String[] args) {
SpinLockDemo spinLockDemo=new SpinLockDemo();
new Thread(() -> {
System.out.println(Thread.currentThread().getName()+"嘗試獲取自旋鎖");
spinLockDemo.lock();
System.out.println(Thread.currentThread().getName()+"獲取自旋鎖成功");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
spinLockDemo.unlock();
System.out.println(Thread.currentThread().getName()+"釋放自旋鎖");
}).start();
new Thread(() -> {
System.out.println(Thread.currentThread().getName()+"嘗試獲取自旋鎖");
spinLockDemo.lock();
System.out.println(Thread.currentThread().getName()+"獲取自旋鎖成功");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
spinLockDemo.unlock();
System.out.println(Thread.currentThread().getName()+"釋放自旋鎖");
}).start();
}
}Thread-0嘗試獲取自旋鎖
Thread-0獲取自旋鎖成功
Thread-1嘗試獲取自旋鎖
Thread-1自旋鎖獲取失敗,重新獲取中
Thread-1自旋鎖獲取失敗,重新獲取中
Thread-1自旋鎖獲取失敗,重新獲取中
Thread-1自旋鎖獲取失敗,重新獲取中
我們打開(kāi) AtomicInteger 源碼看一下,這里是個(gè) do while 循環(huán)

自旋鎖的應(yīng)用場(chǎng)景
自旋鎖一般用于多核服務(wù)器,在并發(fā)度不是特別搞的情況下,比阻塞鎖效率高
另外,自旋鎖適用于臨界區(qū)較小的情況,否則如果臨界區(qū)很大,(線程一旦拿到鎖,很多之后才會(huì)釋放),那也是不適合的
到此這篇關(guān)于Java中的自旋鎖與阻塞鎖詳解的文章就介紹到這了,更多相關(guān)自旋鎖與阻塞鎖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java生產(chǎn)者消費(fèi)者的三種實(shí)現(xiàn)方式
這篇文章主要介紹了Java生產(chǎn)者消費(fèi)者的三種實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-07-07
Java中的自動(dòng)裝箱與自動(dòng)拆箱的實(shí)現(xiàn)
自動(dòng)裝箱和自動(dòng)拆箱使得我們?cè)谑褂没緮?shù)據(jù)類(lèi)型時(shí)更加方便,同時(shí)也提高了代碼的可讀性和健壯性,本文將詳細(xì)介紹Java中的自動(dòng)裝箱和自動(dòng)拆箱機(jī)制,感興趣的可以了解一下2023-08-08
SpringBoot連接Nacos集群報(bào)400問(wèn)題及完美解決方法
這篇文章主要介紹了解決SpringBoot連接Nacos集群報(bào)400問(wèn)題?,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-02-02
Java9新特性Stream流API優(yōu)化與增強(qiáng)
這篇文章主要為大家介紹了Java9新特性Stream流API優(yōu)化與增強(qiáng)的用法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助祝大家多多進(jìn)步,早日升職加薪2022-03-03

