Java實作cas指令的無鎖程式設計的實例
這篇文章主要介紹了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中文網其他相關文章!

熱AI工具

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

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

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

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

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

Java 8引入了Stream API,提供了一種強大且表達力豐富的處理數據集合的方式。然而,使用Stream時,一個常見問題是:如何從forEach操作中中斷或返回? 傳統循環允許提前中斷或返回,但Stream的forEach方法並不直接支持這種方式。本文將解釋原因,並探討在Stream處理系統中實現提前終止的替代方法。 延伸閱讀: Java Stream API改進 理解Stream forEach forEach方法是一個終端操作,它對Stream中的每個元素執行一個操作。它的設計意圖是處

PHP是一種廣泛應用於服務器端的腳本語言,特別適合web開發。 1.PHP可以嵌入HTML,處理HTTP請求和響應,支持多種數據庫。 2.PHP用於生成動態網頁內容,處理表單數據,訪問數據庫等,具有強大的社區支持和開源資源。 3.PHP是解釋型語言,執行過程包括詞法分析、語法分析、編譯和執行。 4.PHP可以與MySQL結合用於用戶註冊系統等高級應用。 5.調試PHP時,可使用error_reporting()和var_dump()等函數。 6.優化PHP代碼可通過緩存機制、優化數據庫查詢和使用內置函數。 7

PHP和Python各有優勢,選擇應基於項目需求。 1.PHP適合web開發,語法簡單,執行效率高。 2.Python適用於數據科學和機器學習,語法簡潔,庫豐富。

PHP適合web開發,特別是在快速開發和處理動態內容方面表現出色,但不擅長數據科學和企業級應用。與Python相比,PHP在web開發中更具優勢,但在數據科學領域不如Python;與Java相比,PHP在企業級應用中表現較差,但在web開發中更靈活;與JavaScript相比,PHP在後端開發中更簡潔,但在前端開發中不如JavaScript。

PHP和Python各有優勢,適合不同場景。 1.PHP適用於web開發,提供內置web服務器和豐富函數庫。 2.Python適合數據科學和機器學習,語法簡潔且有強大標準庫。選擇時應根據項目需求決定。

膠囊是一種三維幾何圖形,由一個圓柱體和兩端各一個半球體組成。膠囊的體積可以通過將圓柱體的體積和兩端半球體的體積相加來計算。本教程將討論如何使用不同的方法在Java中計算給定膠囊的體積。 膠囊體積公式 膠囊體積的公式如下: 膠囊體積 = 圓柱體體積 兩個半球體體積 其中, r: 半球體的半徑。 h: 圓柱體的高度(不包括半球體)。 例子 1 輸入 半徑 = 5 單位 高度 = 10 單位 輸出 體積 = 1570.8 立方單位 解釋 使用公式計算體積: 體積 = π × r2 × h (4

PHPhassignificantlyimpactedwebdevelopmentandextendsbeyondit.1)ItpowersmajorplatformslikeWordPressandexcelsindatabaseinteractions.2)PHP'sadaptabilityallowsittoscaleforlargeapplicationsusingframeworkslikeLaravel.3)Beyondweb,PHPisusedincommand-linescrip

PHP成為許多網站首選技術棧的原因包括其易用性、強大社區支持和廣泛應用。 1)易於學習和使用,適合初學者。 2)擁有龐大的開發者社區,資源豐富。 3)廣泛應用於WordPress、Drupal等平台。 4)與Web服務器緊密集成,簡化開發部署。
