1. 程式人生 > 程式設計 >例項講解Java 自旋鎖

例項講解Java 自旋鎖

  一直以來不是怎麼清楚自旋鎖,最近有點時間,好好的學習了一下;

  所謂的自旋鎖在我的理解就是多個執行緒在嘗試獲取鎖的時候,其中一個執行緒獲取鎖之後,其他的執行緒都處在一直嘗試獲取鎖的狀態,不會阻塞!!!那麼什麼叫做一直嘗試獲取鎖呢?就是一個迴圈,比較經典的是AtomicInteger中的一個updateAndGet方法,下圖所示(當然也可以直接看unsafe類中的getAndAddInt等類似方法);

  我們可以看出在while迴圈中使用CAS去嘗試更新一個變數,如果更新失敗,就會一直在這個迴圈中一直在嘗試;成功的話,就可以到最後的return語句;

  由此我們可以大概知道如果自旋的執行緒過多,那麼CPU的資源就會被大量消耗!!!

例項講解Java 自旋鎖

  順便提一個東西叫做原子引用,官方提供了AtomicInteger,AtomicBoolean等原子類,那麼如果我們自己定義的類也需要有原子性怎麼辦呢?所以官方提供了一個AtomicReference類,可以將我們自己定義的類封裝一下,就成了我們自己的原子類,例如AtomicReference<Student> atomicReference = new AtomicReference<>();,然後我們對Student的例項進行CAS各種CAS操作;

  栗子:

package TestMain;


import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

@Slf4j
public class TestMain80 {
  //一個Thread類的原子引用
  AtomicReference<Thread> atomicReference = new AtomicReference<>();

  //加鎖的方法
  public void myLock() {
    Thread currentThread = Thread.currentThread();
    log.info("myLock--Thread:{}",currentThread.getName());
    //這個就是自旋鎖的核心,利用CAS比較當前原子引用中是否為null,如果是null,就把當前執行緒A放到裡面去,
    // 此時執行緒B再到這裡,那麼就會CAS失敗,一直在while迴圈中
    while (!atomicReference.compareAndSet(null,currentThread)) {

    }
  }

  //解鎖的方法
  public void myUnlock() {
    Thread currentThread = Thread.currentThread();
    //CAS比較原子引用中是不是執行緒A,是的話就更新為null,此時在上面while中一直在自旋的執行緒B就可以跳出來了
    atomicReference.compareAndSet(currentThread,null);
    log.info("myUnlock--Thread:{}",currentThread.getName());
  }

  public static void main(String[] args) {
    TestMain80 testMain80 = new TestMain80();

    //執行緒A,首先加鎖,然後等3秒中,然後釋放鎖
    new Thread(() -> {
      testMain80.myLock();
      try {
        TimeUnit.SECONDS.sleep(3);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      testMain80.myUnlock();
    },"A").start();

    //主執行緒等1秒,保證A執行緒先執行
    try {
      TimeUnit.SECONDS.sleep(1);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }

    //執行緒B,加鎖再釋放鎖
    new Thread(() -> {
      testMain80.myLock();
      testMain80.myUnlock();
    },"B").start();


  }
}

例項講解Java 自旋鎖

  上面的就是一個自旋鎖的栗子,執行結果中首先是執行A執行緒的myLock方法,獲取鎖成功,之後的B執行緒雖然也會執行mylock方法,但是會在while迴圈中一直阻塞,直到執行緒A呼叫了myUnlock方法釋放鎖,最後兩行才會打印出來;

以上就是例項講解Java 自旋鎖的詳細內容,更多關於Java 自旋鎖的資料請關注我們其它相關文章!