分析Java非阻塞算法Lock-Free的實(shí)現(xiàn)
非阻塞的棧
我們先使用CAS來(lái)構(gòu)建幾個(gè)非阻塞的棧。棧是最簡(jiǎn)單的鏈?zhǔn)浇Y(jié)構(gòu),其本質(zhì)是一個(gè)鏈表,而鏈表的根節(jié)點(diǎn)就是棧頂。
我們先構(gòu)建Node數(shù)據(jù)結(jié)構(gòu):
public class Node<E> {
public final E item;
public Node<E> next;
public Node(E item){
this.item=item;
}
}
這個(gè)Node保存了內(nèi)存item和它的下一個(gè)節(jié)點(diǎn)next。
然后我們構(gòu)建非阻塞的棧,在該棧中我們需要實(shí)現(xiàn)pop和push方法,我們使用一個(gè)Atomic類(lèi)來(lái)保存top節(jié)點(diǎn)的引用,在pop和push之前調(diào)用compareAndSet命令來(lái)保證命令的原子性。同時(shí),我們需要不斷的循環(huán),以保證在線(xiàn)程沖突的時(shí)候能夠重試更新。
public class ConcurrentStack<E> {
AtomicReference<Node<E>> top= new AtomicReference<>();
public void push(E item){
Node<E> newNode= new Node<>(item);
Node<E> oldNode;
do{
oldNode=top.get();
newNode.next= oldNode;
}while(!top.compareAndSet(oldNode, newNode));
}
public E pop(){
Node<E> oldNode;
Node<E> newNode;
do {
oldNode = top.get();
if(oldNode == null){
return null;
}
newNode=oldNode.next;
}while(!top.compareAndSet(oldNode, newNode));
return oldNode.item;
}
}
非阻塞的鏈表
構(gòu)建鏈表要比構(gòu)建棧復(fù)雜。因?yàn)槲覀円S持頭尾兩個(gè)指針。以put方法來(lái)說(shuō),我們需要執(zhí)行兩步操作:1. 在尾部插入新的節(jié)點(diǎn)。2.將尾部指針指向最新的節(jié)點(diǎn)。
我們使用CAS最多只能保證其中的一步是原子執(zhí)行。那么對(duì)于1和2的組合步驟該怎么處理呢?
我們?cè)僮屑?xì)考慮考慮,其實(shí)1和2并不一定要在同一個(gè)線(xiàn)程中執(zhí)行,其他線(xiàn)程在檢測(cè)到有線(xiàn)程插入了節(jié)點(diǎn),但是沒(méi)有將tail指向最后的節(jié)點(diǎn)時(shí),完全幫忙完成這個(gè)操作。
我們看下具體的代碼實(shí)現(xiàn):
public class LinkedNode<E> {
public final E item;
public final AtomicReference<LinkedNode<E>> next;
public LinkedNode(E item, LinkedNode<E> next){
this.item=item;
this.next=new AtomicReference<>(next);
}
}
先構(gòu)建一個(gè)LinkedNode類(lèi)。
public class LinkedQueue<E> {
private final LinkedNode<E> nullNode= new LinkedNode<>(null, null);
private final AtomicReference<LinkedNode<E>> head= new AtomicReference<>(nullNode);
private final AtomicReference<LinkedNode<E>> tail= new AtomicReference<>(nullNode);
public boolean put(E item){
LinkedNode<E> newNode = new LinkedNode<>(item, null);
while (true){
LinkedNode<E> currentTail= tail.get();
LinkedNode<E> tailNext= currentTail.next.get();
if(currentTail == tail.get()){
if (tailNext != null) {
//有其他的線(xiàn)程已經(jīng)插入了一個(gè)節(jié)點(diǎn),但是還沒(méi)有將tail指向最新的節(jié)點(diǎn)
tail.compareAndSet(currentTail, tailNext);
}else{
//沒(méi)有其他的線(xiàn)程插入節(jié)點(diǎn),那么做兩件事情:1. 插入新節(jié)點(diǎn),2.將tail指向最新的節(jié)點(diǎn)
if(currentTail.next.compareAndSet(null, newNode)){
tail.compareAndSet(currentTail, newNode);
}
}
}
}
}
}
以上就是分析Java非阻塞算法Lock-Free的實(shí)現(xiàn)的詳細(xì)內(nèi)容,更多關(guān)于Java非阻塞算法Lock-Free的實(shí)現(xiàn)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
SpringBoot日程管理Quartz與定時(shí)任務(wù)Task實(shí)現(xiàn)詳解
定時(shí)任務(wù)是企業(yè)級(jí)開(kāi)發(fā)中必不可少的組成部分,諸如長(zhǎng)周期業(yè)務(wù)數(shù)據(jù)的計(jì)算,例如年度報(bào)表,諸如系統(tǒng)臟數(shù)據(jù)的處理,再比如系統(tǒng)性能監(jiān)控報(bào)告,還有搶購(gòu)類(lèi)活動(dòng)的商品上架,這些都離不開(kāi)定時(shí)任務(wù)。本節(jié)將介紹兩種不同的定時(shí)任務(wù)技術(shù)2022-09-09
java 實(shí)現(xiàn)數(shù)組擴(kuò)容與縮容案例
這篇文章主要介紹了java 實(shí)現(xiàn)數(shù)組擴(kuò)容與縮容案例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-02-02
Spring事務(wù)@Transactional注解四種不生效案例場(chǎng)景分析
這篇文章主要為大家介紹了Spring事務(wù)@Transactional注解四種不生效的案例場(chǎng)景示例分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07
SpringBoot3實(shí)現(xiàn)上傳圖片并返回路徑讓前端顯示圖片
這篇文章主要介紹了SpringBoot3實(shí)現(xiàn)上傳圖片并返回路徑讓前端顯示圖片,文中通過(guò)圖文和代碼講解的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2024-12-12
支持SpEL表達(dá)式的自定義日志注解@SysLog介紹
這篇文章主要介紹了支持SpEL表達(dá)式的自定義日志注解@SysLog,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-02-02
如何基于spring security實(shí)現(xiàn)在線(xiàn)用戶(hù)統(tǒng)計(jì)
這篇文章主要介紹了如何基于spring security實(shí)現(xiàn)在線(xiàn)用戶(hù)統(tǒng)計(jì),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-06-06
java如何接收和發(fā)送ASCII數(shù)據(jù)
這篇文章主要介紹了java如何接收和發(fā)送ASCII數(shù)據(jù)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-09-09
圖書(shū)信息管理java實(shí)現(xiàn)代碼
這篇文章主要為大家詳細(xì)介紹了圖書(shū)信息管理java實(shí)現(xiàn)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-01-01
利用Java查看進(jìn)程內(nèi)存占用情況的實(shí)現(xiàn)方法
在系統(tǒng)監(jiān)控和性能調(diào)優(yōu)中,了解各個(gè)進(jìn)程的內(nèi)存占用情況是非常重要的一環(huán),通過(guò)查看進(jìn)程內(nèi)存使用情況,開(kāi)發(fā)者和運(yùn)維人員可以及時(shí)發(fā)現(xiàn)異常進(jìn)程、資源瓶頸和內(nèi)存泄漏問(wèn)題,本項(xiàng)目旨在使用 Java 編寫(xiě)一個(gè)簡(jiǎn)單的程序,通過(guò)調(diào)用操作系統(tǒng)的命令來(lái)獲取系統(tǒng)中各個(gè)進(jìn)程的內(nèi)存使用情況2025-03-03

