非阻塞算法(Lock-Free)的实现
文章目錄
- 非阻塞的棧
- 非阻塞的鏈表
非阻塞算法(Lock-Free)的實(shí)現(xiàn)
上篇文章我們講到了使用鎖會(huì)帶來的各種缺點(diǎn),本文將會(huì)講解如何使用非阻塞算法。非阻塞算法一般會(huì)使用CAS來協(xié)調(diào)線程的操作。
雖然非阻塞算法有諸多優(yōu)點(diǎn),但是在實(shí)現(xiàn)上要比基于鎖的算法更加繁瑣和負(fù)責(zé)。
本文將會(huì)介紹兩個(gè)是用非阻塞算法實(shí)現(xiàn)的數(shù)據(jù)結(jié)構(gòu)。
非阻塞的棧
我們先使用CAS來構(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類來保存top節(jié)點(diǎn)的引用,在pop和push之前調(diào)用compareAndSet命令來保證命令的原子性。同時(shí),我們需要不斷的循環(huá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方法來說,我們需要執(zhí)行兩步操作:1. 在尾部插入新的節(jié)點(diǎn)。2.將尾部指針指向最新的節(jié)點(diǎn)。
我們使用CAS最多只能保證其中的一步是原子執(zhí)行。那么對(duì)于1和2的組合步驟該怎么處理呢?
我們?cè)僮屑?xì)考慮考慮,其實(shí)1和2并不一定要在同一個(gè)線程中執(zhí)行,其他線程在檢測(cè)到有線程插入了節(jié)點(diǎn),但是沒有將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類。
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) {//有其他的線程已經(jīng)插入了一個(gè)節(jié)點(diǎn),但是還沒有將tail指向最新的節(jié)點(diǎn)tail.compareAndSet(currentTail, tailNext);}else{//沒有其他的線程插入節(jié)點(diǎn),那么做兩件事情:1. 插入新節(jié)點(diǎn),2.將tail指向最新的節(jié)點(diǎn)if(currentTail.next.compareAndSet(null, newNode)){tail.compareAndSet(currentTail, newNode);}}}}} }本文的例子可以參考https://github.com/ddean2009/learn-java-concurrency/tree/master/nonblock
更多精彩內(nèi)容且看:
- 區(qū)塊鏈從入門到放棄系列教程-涵蓋密碼學(xué),超級(jí)賬本,以太坊,Libra,比特幣等持續(xù)更新
- Spring Boot 2.X系列教程:七天從無到有掌握Spring Boot-持續(xù)更新
- Spring 5.X系列教程:滿足你對(duì)Spring5的一切想象-持續(xù)更新
- java程序員從小工到專家成神之路(2020版)-持續(xù)更新中,附詳細(xì)文章教程
更多內(nèi)容請(qǐng)?jiān)L問 http://www.flydean.com/java-lock-free/
總結(jié)
以上是生活随笔為你收集整理的非阻塞算法(Lock-Free)的实现的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 非阻塞同步机制和CAS
- 下一篇: java内存模型(JMM)和happen