Java中的自旋鎖與阻塞鎖詳解
自旋鎖
阻塞或者喚醒一個Java線程需要操作系統(tǒng)切換CPU 狀態(tài)來完成,這種狀態(tài)轉(zhuǎn)換 需要耗費處理器時間 如果同步代碼塊到代碼過于簡單,狀態(tài)轉(zhuǎn)換到時間有kennel比用戶執(zhí)行代碼到時間還長 在許多場景下,同步資源到鎖定時間短,為了這小段時間切換線程,線程的掛起和恢復(fù)可能會讓系統(tǒng)得不償失,
這里是為了當(dāng)前線程“ 稍等一下”, 我們需要讓當(dāng)前線程進行自旋 ,如果自旋完成后前面鎖定同步資源的線程以及釋放了鎖,那么當(dāng)前線程就沒必要阻塞,而是直接獲取同步資源,從而避免線程的開銷 阻塞鎖和自旋鎖相反,阻塞鎖如果沒有拿到鎖,就會直接阻塞,知道被喚醒
阻塞鎖
阻塞鎖是指當(dāng)線程嘗試獲取鎖失敗時,線程進入阻塞狀態(tài),直到接收信號后被喚醒.(線程的狀態(tài)包括新建、就緒、運行、阻塞及死亡)在JAVA中,能夠喚醒阻塞線程的操作包括Object.notify, Object.notifyAll, Condition.signal, LockSupport.unpark(JUC中引入)
原理和源碼分析
在 jdk 1.5 及以上并發(fā)框架 Java.util.concurrent 的 atomic 下 都是自旋鎖實現(xiàn)的
AtomicInteger 的實現(xiàn) :自旋鎖實現(xiàn)原理是CAS AtomicInteger 中是調(diào)用底層unsafe 進行自增操作的源碼中的 do-while 循環(huán)就是一個自旋操作,如果修改過程中一踏線程競爭導(dǎo)致修改失敗,就在while 死循環(huán),直至成功
package com.dimple.test; /** * 本實例演示下線程的自旋鎖的實現(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自旋鎖獲取失敗,重新獲取中
我們打開 AtomicInteger 源碼看一下,這里是個 do while 循環(huán)
自旋鎖的應(yīng)用場景
自旋鎖一般用于多核服務(wù)器,在并發(fā)度不是特別搞的情況下,比阻塞鎖效率高
另外,自旋鎖適用于臨界區(qū)較小的情況,否則如果臨界區(qū)很大,(線程一旦拿到鎖,很多之后才會釋放),那也是不適合的
到此這篇關(guān)于Java中的自旋鎖與阻塞鎖詳解的文章就介紹到這了,更多相關(guān)自旋鎖與阻塞鎖內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot連接Nacos集群報400問題及完美解決方法
這篇文章主要介紹了解決SpringBoot連接Nacos集群報400問題?,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-02-02