搜尋
首頁Javajava教程Java實作cas指令的無鎖程式設計的實例

Java實作cas指令的無鎖程式設計的實例

Sep 15, 2017 am 11:07 AM
java實例程式設計

這篇文章主要介紹了Java語言中cas指令的無鎖定程式實作實例,具有一定參考價值,需要的朋友可以了解下。

最開始接觸到相關的內容應該是從volatile關鍵字開始的吧,知道它可以保證變數的可見性,而且利用它可以實現讀與寫的原子操作。 。 。但是要實現一些複合的操作volatile就無能為力了。 。 。最典型的代表是遞增和遞減的操作。 。 。 。

我們知道,在並發的環境下,要實現資料的一致性,最簡單的方式就是加鎖,保證在同一時刻只有一個執行緒可以對資料進行操作。 。 。 。例如一個計數器,我們可以用如下的方式來實現:


public class Counter {
  private volatile int a = 0;
  public synchronized int incrAndGet(int number) {
    this.a += number;
    return a;
  } 
  public synchronized int get() {
    return a;
  }
}

我們對操作都用synchronized關鍵字進行修飾,並保證對屬性a的同步存取。 。 。這樣子確實可以保證在並發環境下a的一致性,但是由於使用了鎖,鎖的開銷,線程的調度等等會使得程式的伸縮性受到了限制,於是就有了很多無鎖的實現方式。 。 。 。

其實這些無鎖的方法都利用了處理器所提供的一些CAS(compare and switch)指令,這個CAS到底乾了啥事情呢,可以用下面這個方法來說明CAS所代表的語意:


public synchronized int compareAndSwap(int expect, int newValue) {
    int old = this.a;
    if (old == expect) {
      this.a = newValue;
    }
    return old;
  }

好吧,透過程式碼應該對CAS語意的標書很清楚了吧,好像現在大多數的處理器都實作了原子的CAS指令了吧。 。
好啦,那麼接下來來看看在java中CAS都用在了什麼地方了吧,首先來看AtomicInteger類型吧,這個是並發庫裡面提供的一個類型:


#
private volatile int value;

這個是內部定義的屬性吧,用來保存值,由於是volatile類型的,所以可以保證執行緒之間的可見性以及讀寫的原子性。 。 。
那麼接下來來看看幾個比較常用的方法:


public final int addAndGet(int delta) {
  for (;;) {
    int current = get();
    int next = current + delta;
    if (compareAndSet(current, next))
      return next;
  }
}

這個方法的作用是在目前值的基礎上加上delta,這裡可以看到整個方法中並沒有加鎖,這程式碼其實就算是java中實作無鎖定計數器的方法,這裡compareAndSet方法的定義如下:


public final boolean compareAndSet(int expect, int update) {
  return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}

由於呼叫了unsafe的方法,所以這個就無能為力了,其實應該可以猜到JVM呼叫了處理器本身的CAS指令來實現原子的操作。 。 。

基本上AtomicInteger類型的重要方法都是採用無鎖的方式實現的。 。因此在並發環境下,用這種類型能有更好的性能。 。 。
上面算是搞定了在java中實現無鎖的計數器,接下來來看看如何實現無鎖棧,直接貼代碼了,代碼是從《JAVA並發編程實戰》中模仿下來的:


package concurrenttest;
import java.util.concurrent.atomic.AtomicReference;
public class ConcurrentStack<e> {
  AtomicReference<node<e>> top = new AtomicReference<node<e>>();
  public void push(E item) {
    Node<e> newHead = new Node<e>(item);
    Node<e> oldHead;
    while (true) {
      oldHead = top.get();
      newHead.next = oldHead;
      if (top.compareAndSet(oldHead, newHead)) {
        return;
      }
    }
  }
  public E pop() {
    while (true) {
      Node<e> oldHead = top.get();
      if (oldHead == null) {
        return null;
      }
      Node<e> newHead = oldHead.next;
      if (top.compareAndSet(oldHead, newHead)) {
        return oldHead.item;
      }
    }
  }
  private static class Node<e> {
    public final E item;
    public Node<e> next;
     
    public Node(E item) {
      this.item = item;
    }
  }
}

好啦,上面的程式碼就算是實作了一個無鎖的棧,簡單吧。 。 。在並發環境中,無鎖定的資料結構伸縮性能夠比用鎖好得多。 。 。
在提到無鎖定程式設計的時候,就不得不提到無鎖定佇列,其實在concurrent函式庫中已經提供了無鎖定佇列的實作:ConcurrentLinkedQueue,我們來看看它的重要的方法實作吧:


public boolean offer(E e) {
  checkNotNull(e);
  final Node<e> newNode = new Node<e>(e);
  for (Node<e> t = tail, p = t;;) {
    Node<e> q = p.next;
    if (q == null) {
      // p is last node
      if (p.casNext(null, newNode)) {
        // Successful CAS is the linearization point
        // for e to become an element of this queue,
        // and for newNode to become "live".
        if (p != t) // hop two nodes at a time
          casTail(t, newNode); // Failure is OK.
        return true;
      }
      // Lost CAS race to another thread; re-read next
    }
    else if (p == q)
      // We have fallen off list. If tail is unchanged, it
      // will also be off-list, in which case we need to
      // jump to head, from which all live nodes are always
      // reachable. Else the new tail is a better bet.
      p = (t != (t = tail)) ? t : head;
    else
      // Check for tail updates after two hops.
      p = (p != t && t != (t = tail)) ? t : q;
  }
}

這個方法用於在佇列的尾部添加元素,這裡可以看到沒有加鎖,對於具體的無鎖演算法,採用的是Michael-Scott提出的非阻塞鍊錶連結演算法。 。 。具體是怎麼樣子的,可以到《JAVA並發程式設計實戰》去看吧,有比較詳細的介紹。

另外對於其他方法,其實都是採用無鎖的方式實現的。

最後,在實際的程式設計中,在並發環境中最好還是採用這些無鎖的實現,畢竟它的伸縮性更好。

總結

#

以上是Java實作cas指令的無鎖程式設計的實例的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
說明JVM如何充當Java代碼和基礎操作系統之間的中介。說明JVM如何充當Java代碼和基礎操作系統之間的中介。Apr 29, 2025 am 12:23 AM

JVM的工作原理是將Java代碼轉換為機器碼並管理資源。 1)類加載:加載.class文件到內存。 2)運行時數據區:管理內存區域。 3)執行引擎:解釋或編譯執行字節碼。 4)本地方法接口:通過JNI與操作系統交互。

解釋Java虛擬機(JVM)在Java平台獨立性中的作用。解釋Java虛擬機(JVM)在Java平台獨立性中的作用。Apr 29, 2025 am 12:21 AM

JVM使Java實現跨平台運行。 1)JVM加載、驗證和執行字節碼。 2)JVM的工作包括類加載、字節碼驗證、解釋執行和內存管理。 3)JVM支持高級功能如動態類加載和反射。

您將採取哪些步驟來確保Java應用程序在不同的操作系統上正確運行?您將採取哪些步驟來確保Java應用程序在不同的操作系統上正確運行?Apr 29, 2025 am 12:11 AM

Java應用可通過以下步驟在不同操作系統上運行:1)使用File或Paths類處理文件路徑;2)通過System.getenv()設置和獲取環境變量;3)利用Maven或Gradle管理依賴並測試。 Java的跨平台能力依賴於JVM的抽象層,但仍需手動處理某些操作系統特定的功能。

Java是否需要特定於平台的配置或調整區域?Java是否需要特定於平台的配置或調整區域?Apr 29, 2025 am 12:11 AM

Java在不同平台上需要進行特定配置和調優。 1)調整JVM參數,如-Xms和-Xmx設置堆大小。 2)選擇合適的垃圾回收策略,如ParallelGC或G1GC。 3)配置Native庫以適應不同平台,這些措施能讓Java應用在各種環境中發揮最佳性能。

哪些工具或庫可以幫助您解決Java開發中特定於平台的挑戰?哪些工具或庫可以幫助您解決Java開發中特定於平台的挑戰?Apr 29, 2025 am 12:01 AM

Osgi,Apachecommonslang,JNA和JvMoptionsareeForhandlingForhandlingPlatform-specificchallengesinjava.1)osgimanagesdeppedendendencenciesandisolatescomponents.2)apachecommonslangprovidesitorityfunctions.3)

JVM如何在不同平台上管理垃圾收集?JVM如何在不同平台上管理垃圾收集?Apr 28, 2025 am 12:23 AM

JVMmanagesgarbagecollectionacrossplatformseffectivelybyusingagenerationalapproachandadaptingtoOSandhardwaredifferences.ItemploysvariouscollectorslikeSerial,Parallel,CMS,andG1,eachsuitedfordifferentscenarios.Performancecanbetunedwithflagslike-XX:NewRa

為什麼Java代碼可以在不同的操作系統上運行,而無需修改?為什麼Java代碼可以在不同的操作系統上運行,而無需修改?Apr 28, 2025 am 12:14 AM

Java代碼可以在不同操作系統上無需修改即可運行,這是因為Java的“一次編寫,到處運行”哲學,由Java虛擬機(JVM)實現。 JVM作為編譯後的Java字節碼與操作系統之間的中介,將字節碼翻譯成特定機器指令,確保程序在任何安裝了JVM的平台上都能獨立運行。

描述編譯和執行Java程序的過程,突出平台獨立性。描述編譯和執行Java程序的過程,突出平台獨立性。Apr 28, 2025 am 12:08 AM

Java程序的編譯和執行通過字節碼和JVM實現平台獨立性。 1)編寫Java源碼並編譯成字節碼。 2)使用JVM在任何平台上執行字節碼,確保代碼的跨平台運行。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

Dreamweaver Mac版

Dreamweaver Mac版

視覺化網頁開發工具

mPDF

mPDF

mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版

Atom編輯器mac版下載

Atom編輯器mac版下載

最受歡迎的的開源編輯器

PhpStorm Mac 版本

PhpStorm Mac 版本

最新(2018.2.1 )專業的PHP整合開發工具