真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

一篇文章輕松搞懂Java中的自旋鎖

前言

10年積累的成都網(wǎng)站制作、做網(wǎng)站經(jīng)驗,可以快速應(yīng)對客戶對網(wǎng)站的新想法和需求。提供各種問題對應(yīng)的解決方案。讓選擇我們的客戶得到更好、更有力的網(wǎng)絡(luò)服務(wù)。我雖然不認識你,你也不認識我。但先網(wǎng)站策劃后付款的網(wǎng)站建設(shè)流程,更有沙雅免費網(wǎng)站建設(shè)讓你可以放心的選擇與我們合作。

鎖作為并發(fā)共享數(shù)據(jù),保證一致性的工具,在JAVA平臺有多種實現(xiàn)(如 synchronized 和 ReentrantLock等等 ) 。這些已經(jīng)寫好提供的鎖為我們開發(fā)提供了便利。

在之前的文章《一文徹底搞懂面試中常問的各種“鎖” 》中介紹了Java中的各種“鎖”,可能對于不是很了解這些概念的同學(xué)來說會覺得有點繞,所以我決定拆分出來,逐步詳細的介紹一下這些鎖的來龍去脈,那么這篇文章就先來會一會“自旋鎖”。

正文

出現(xiàn)原因

在我們的程序中,如果存在著大量的互斥同步代碼,當(dāng)出現(xiàn)高并發(fā)的時候,系統(tǒng)內(nèi)核態(tài)就需要不斷的去掛起線程和恢復(fù)線程,頻繁的此類操作會對我們系統(tǒng)的并發(fā)性能有一定影響。同時聰明的JVM開發(fā)團隊也發(fā)現(xiàn),在程序的執(zhí)行過程中鎖定“共享資源“的時間片是極短的,如果僅僅是為了這點時間而去不斷掛起、恢復(fù)線程的話,消耗的時間可能會更長,那就“撿了芝麻丟了西瓜”了。

而在一個多核的機器中,多個線程是可以并行執(zhí)行的。如果當(dāng)后面請求鎖的線程沒拿到鎖的時候,不掛起線程,而是繼續(xù)占用處理器的執(zhí)行時間,讓當(dāng)前線程執(zhí)行一個忙循環(huán)(自旋操作),也就是不斷在盯著持有鎖的線程是否已經(jīng)釋放鎖,那么這就是傳說中的自旋鎖了。

自旋鎖開啟

雖然在JDK1.4.2的時候就引入了自旋鎖,但是需要使用“-XX:+UseSpinning”參數(shù)來開啟。在到了JDK1.6以后,就已經(jīng)是默認開啟了。下面我們自己來實現(xiàn)一個基于CAS的簡易版自旋鎖。

public class SimpleSpinningLock {

 /**
 * 持有鎖的線程,null表示鎖未被線程持有
 */
 private AtomicReference ref = new AtomicReference<>();

 public void lock(){
 Thread currentThread = Thread.currentThread();
 while(!ref.compareAndSet(null, currentThread)){
  //當(dāng)ref為null的時候compareAndSet返回true,反之為false
  //通過循環(huán)不斷的自旋判斷鎖是否被其他線程持有
 }
 }

 public void unLock() {
 Thread cur = Thread.currentThread();
 if(ref.get() != cur){
  //exception ...
 }
 ref.set(null);
 }
}

簡簡單單幾行代碼就實現(xiàn)了一個簡陋的自旋鎖,下面我們來測試一下

public class TestLock {

 static int count = 0;

 public static void main(String[] args) throws InterruptedException {
 ExecutorService executorService = Executors.newFixedThreadPool(100);
 CountDownLatch countDownLatch = new CountDownLatch(100);
 SimpleSpinningLock simpleSpinningLock = new SimpleSpinningLock();
 for (int i = 0 ; i < 100 ; i++){
  executorService.execute(new Runnable() {
  @Override
  public void run() {
   simpleSpinningLock.lock();
   ++count;
   simpleSpinningLock.unLock();
   countDownLatch.countDown();
  }
  });

 }
 countDownLatch.await();
 System.out.println(count);
 }
}

// 多次執(zhí)行輸出均為:100 ,實現(xiàn)了鎖的基本功能

通過上面的代碼可以看出,自旋就是在循環(huán)判斷條件是否滿足,那么會有什么問題嗎?如果鎖被占用很長時間的話,自旋的線程等待的時間也會變長,白白浪費掉處理器資源。因此在JDK中,自旋操作默認10次,我們可以通過參數(shù)“-XX:PreBlockSpin”來設(shè)置,當(dāng)超過來此參數(shù)的值,則會使用傳統(tǒng)的線程掛起方式來等待鎖釋放。

自適應(yīng)自旋鎖

隨著JDK的更新,在1.6的時候,又出現(xiàn)了一個叫做“自適應(yīng)自旋鎖”的玩意。它的出現(xiàn)使得自旋操作變得聰明起來,不再跟之前一樣死板。所謂的“自適應(yīng)”意味著對于同一個鎖對象,線程的自旋時間是根據(jù)上一個持有該鎖的線程的自旋時間以及狀態(tài)來確定的。例如對于A鎖對象來說,如果一個線程剛剛通過自旋獲得到了鎖,并且該線程也在運行中,那么JVM會認為此次自旋操作也是有很大的機會可以拿到鎖,因此它會讓自旋的時間相對延長。但是如果對于B鎖對象自旋操作很少成功的話,JVM甚至可能直接忽略自旋操作。因此,自適應(yīng)自旋鎖是一個更加智能,對我們的業(yè)務(wù)性能更加友好的一個鎖。

結(jié)語

本來想著在一篇文章里面把“自旋鎖”,“鎖消除”,“鎖粗化”等一些鎖優(yōu)化的概念都介紹完成的,但是發(fā)現(xiàn)可能篇幅會比較大,對于沒怎么接觸過這一塊的同學(xué)來說理解起來會比較吃力,所以決定分開多個章節(jié)介紹,希望大家都不懂的地方可以多看幾遍,慢慢體會,相信你會有所收獲的。

總結(jié)

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,謝謝大家對創(chuàng)新互聯(lián)的支持。


文章標(biāo)題:一篇文章輕松搞懂Java中的自旋鎖
標(biāo)題URL:http://weahome.cn/article/giedsh.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部