基于单链表实现一个非阻塞的栈

Posted Dream_it_possible!

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于单链表实现一个非阻塞的栈相关的知识,希望对你有一定的参考价值。

        栈是最简单的单链表结构,我们可以通过从单链表的尾插节点、从尾部取出节点实现栈的存取元素。

        我们都知道CAS可以保证操作的原子性和可见性,AtomicReference能和volatile关键字有同样的效果,因此可以结合AtomicReference+CAS实现Push和PoP元素操作的可见性和原子性,每次Push和Pop的时候更新新的Head, 如果有其他线程干扰的情况下,那么修改操作失败。

package com.example.jucdemo.stack;

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 基于单链表实现非阻塞的栈结构
 * AtomicReference+CAS
 *
 * @param <E>
 */

public class ConcurrentStack<E> 

    AtomicReference<Node<E>> top = new AtomicReference<>();


    /**
     * 通过CAS操作,每次取出栈顶元素,取出完毕后,再设置下一个节点为栈顶元素
     *
     * @param item
     */
    public void push(E item) 
        //设置一个新的Node节点
        Node<E> newHead = new Node<>(item);
        Node<E> oldHead;
        do 
            oldHead = top.get();
            newHead.next = oldHead;
         while (!top.compareAndSet(oldHead, newHead));
        System.out.println("push的值为" + item.toString() + ",得到的链表为:" + newHead.traverse());
    


    public E pop() 
        Node<E> newHead;
        Node<E> oldHead;
        do 
            oldHead = top.get();
            if (oldHead == null) 
                return null;
            
            newHead = oldHead.next;
         while (!top.compareAndSet(oldHead, newHead));
        if (newHead != null) 
            System.out.println("pop的值为" + oldHead.item.toString() + ",得到的链表为:" + newHead.traverse());
        
        return oldHead.item;
    


    static class Node<E> 
        private final E item;

        private Node<E> next;

        public Node(E item) 
            this.item = item;
        

        public String traverse() 
            String current = this.item.toString();
            return this.next == null ? current : current + "->" + this.next.traverse();
        
    

    private static ConcurrentStack<Integer> stack = new ConcurrentStack<>();

    public static void main(String[] args) 
        Thread t1 = new Thread(new Task());
        Thread t2 = new Thread(new Task());
        Thread t3 = new Thread(new Task());
        Thread t4 = new Thread(new Task());
        Thread t5 = new Thread(new Task());
        t1.start();
        t2.start();
        t3.start();
        t4.start();
        t5.start();
        try 
            t1.join();
            t2.join();
            t3.join();
            t4.join();
            t5.join();
         catch (InterruptedException e) 
            e.printStackTrace();
        
        System.out.println();
        System.out.println(stack.pop());
        System.out.println(stack.pop());
        System.out.println(stack.pop());
        System.out.println(stack.pop());
        System.out.println(stack.pop());
        System.out.println(stack.pop());
    

    private volatile static AtomicInteger i = new AtomicInteger(0);


    static class Task implements Runnable 

        @Override
        public void run() 
            Integer value = i.getAndIncrement();
            System.out.println(Thread.currentThread().getName() + "push数据:" + value);
            stack.push(value);
        
    



打印结果:

Thread-0push数据:0
Thread-3push数据:3
Thread-2push数据:2
Thread-1push数据:1
Thread-4push数据:4
push的值为0,得到的链表为:0
push的值为2,得到的链表为:2->1->4->0
push的值为1,得到的链表为:1->4->0
push的值为4,得到的链表为:4->0
push的值为3,得到的链表为:3->2->1->4->0

pop的值为3,得到的链表为:2->1->4->0
3
pop的值为2,得到的链表为:1->4->0
2
pop的值为1,得到的链表为:4->0
1
pop的值为4,得到的链表为:0
4
0
null

Process finished with exit code 0

        从打印结果中,我们可以发现,插入的顺序和取出的元素顺序是正好相反的。 

参考: <<Java并发编程实战>> 

以上是关于基于单链表实现一个非阻塞的栈的主要内容,如果未能解决你的问题,请参考以下文章

面试官: 如何用Java实现一个栈?

单链表~增删查改(附代码)~简单实现

面试题5:JS实现从尾到头打印单链表

单链表基本操作

基于C语言的单链表实现

基于C语言的单链表实现