0%

Treiber Stack 无锁并发栈

这里介绍一种无锁并发栈 ——Treiber Stack

基本原理

Treiber Stack 是一种 Lock-Free 无锁的并发栈,由 R. Kent Treiber 于 1986 年提出。其底层原理是借助于 CAS、自旋实现的。Java 的 ForkJoinPool、FutureTask、CompletableFuture 等均应用了 Treiber Stack

入栈、出栈的过程也很简单:

  • 入栈过程:先把入栈元素的 next 指针指向当前最新的的栈顶元素,然后利用 CAS 操作保证修改栈顶指针为 入栈元素 时,没有其他线程进行修改操作。当然,如果栈顶元素发生了修改,则会进行重试
  • 出栈过程:先获取当前最新的栈顶元素,将其作为准备出栈的元素。然后利用 CAS 操作保证修改栈顶指针为 其 next 指针指向的元素 时,没有其他线程进行修改操作。当然,如果栈顶元素发生了修改,则会进行重试

Java 实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
import lombok.Data;
import java.util.concurrent.atomic.AtomicReference;

public class TreiberStack<E> {
/**
* 栈顶指针
*/
private final AtomicReference<Node<E>> stackTop = new AtomicReference<>();

/**
* 入栈
* @param val
*/
public void push(E val) {
Node<E> newHeadNode = new Node<>(val);
Node<E> oldHeadNode;
do{
oldHeadNode = stackTop.get();
newHeadNode.setNext( oldHeadNode );
}while ( !stackTop.compareAndSet(oldHeadNode, newHeadNode) );
}

/**
* 出栈
* @return
*/
public E pop() {
Node<E> newHeadNode;
Node<E> oldHeadNode;

do{
oldHeadNode = stackTop.get();
if( oldHeadNode==null ) {
return null;
}
newHeadNode = oldHeadNode.getNext();
} while ( !stackTop.compareAndSet(oldHeadNode, newHeadNode));
return oldHeadNode.getVal();
}

public int size() {
if( stackTop.get()==null ) {
return 0;
}

int size = 0;
Node<E> current = stackTop.get();
while( current!=null ) {
size++;
current = current.getNext();
}
return size;
}

public boolean isEmpty() {
return size()==0;
}

@Data
public static class Node<E> {
private E val;

private Node<E> next;

public Node(E val) {
this.val = val;
}
}
}
请我喝杯咖啡捏~

欢迎关注我的微信公众号:青灯抽丝

Powered By Valine
v1.5.2