ConcurrentLinkQueue实现进入死锁状态

时间:2013-08-04 08:58:17

标签: java multithreading java.util.concurrent compare-and-swap

我正在学习并发编程,并使用AtomicReference编写了此concurrentLinkeQueue。

以下示例进入死锁状态。请参阅。

 package concurrent.AtomicE;

 import java.util.concurrent.atomic.AtomicReference;

 public class ConcurrentLinkQueue<V> {
private AtomicReference<Node> head = new AtomicReference<Node>();

public void offer(final V data) {
    final Node<V> newNode = new Node<V>(data,Thread.currentThread().getName());
    System.out.println("*********** NEW "+ newNode);
    AtomicReference<Node> pointer = head;
    for(;;){
         if(pointer.get() == null){ // Threads wait here for infinite time
             final boolean success = pointer.compareAndSet(null,newNode);
             System.out.println(Thread.currentThread().getName() +" " + success);
             if(success)
             {
                 System.out.println(Thread.currentThread().getName() +"Returning");
                 return;
             }else{
                 final Node<V> current = pointer.get();
                 pointer = current.next;
                 System.out.println(Thread.currentThread().getName() +" Next Pointer");
             }
        }
    }
}

public void printQueueData(){
    AtomicReference<Node> pointer = head;
    for(;pointer!=null;){
        final Node node = pointer.get();
        System.out.println(node);
        pointer = node.next;
    }
}

private static class Node<V>{
    private AtomicReference<Node> next;
    private volatile V data = null;
    private String threadName = "";

    Node(V data1,String threadName){
        this.data = data1;
        this.threadName = threadName;
    }

    @Override
    public String toString() {
        return  "threadName=" + threadName +
                ", data=" + data;
    }

    private AtomicReference<Node> getNext() {
        return next;
    }

    private void setNext(AtomicReference<Node> next) {
        this.next = next;
    }

    private V getData() {
        return data;
    }

    private void setData(V data) {
        this.data = data;
    }
}

}

      package concurrent.AtomicE;

 import java.util.concurrent.Executors;
 import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;

 public class Main {
private static final ConcurrentLinkQueue<Integer> clq =  new ConcurrentLinkQueue<Integer>();

public static void main(String[] args) throws InterruptedException {
    Task t = new Task();
    Thread t1 = new Thread(t); t1.setName("t1");
    Thread t2 = new Thread(t); t2.setName("t2");
    //Thread t3 = new Thread(t); t3.setName("t3");
    //Thread t4 = new Thread(t); t4.setName("t4");
    //Thread t5 = new Thread(t); t5.setName("t5");

    t1.start();
    t2.start();
    //t3.start();
    //t4.start();
    //t5.start();

    t1.join();
    t2.join();
    //t3.join();
    //t4.join();
    //t5.join();


}

private static class Task implements Runnable{

    @Override
    public void run() {
        for(int i=0;i<5;++i){
            clq.offer(i);
        }
    }
}

}

获取线程转储后,它显示线程在下一行

永远等待
 if(pointer.get() == null){ // Threads wait here for infinite time

你能帮助为什么线程永远在这里等待吗?

[编辑] 解决了它---&gt;

 public class ConcurrentLinkQueue<V> {
  private final AtomicReference<Node> firstNodePointer = new AtomicReference<Node>();

public void offer(final V data) {
    final Node<V> newNode = new Node<V>(data,Thread.currentThread().getName());
    System.out.println(newNode);
    final Node<Integer> firstNode = firstNodePointer.get();
    if(firstNode == null){
        if(firstNodePointer.compareAndSet(null,newNode) == true)
            return;
    }
    boolean success = false;
    Node<Integer> nodePointer = firstNode;
    AtomicReference<Node> atomicRefPointer = firstNodePointer;
    while(!success){
        atomicRefPointer = nodePointer.getNext();
        if(atomicRefPointer.get() == null){
            success = atomicRefPointer.compareAndSet(null,newNode);
        }else{
            nodePointer = atomicRefPointer.get();
        }
    }
}

}

另一种解决方案 - &gt;

      public void fastOffer(final V data){
    final Node<V> newNode = new Node<V>(data,Thread.currentThread().getName());
    System.out.println(newNode);
    AtomicReference<Node> pointer = firstNodePointer;
    for(;;){
            if(pointer.compareAndSet(null,newNode)){
                return;
            }

        pointer = pointer.get().getNext();
    }
}

1 个答案:

答案 0 :(得分:0)

在您的示例条件中,pointer.get() == null总是会返回false,除非您将其分配给head,因为在Node类中null。您可以为其分配默认值并删除空检查。

我建议您更改一下Node类,使其成为不可变的:

 private static class Node<V> {
        private final AtomicReference<Node> next = new AtomicReference<>();
        private final V data;
        private final String threadName;

        Node(V data1, String threadName) {
            this.data = data1;
            this.threadName = threadName;
        }
    }

然后你可以简单地浏览所有元素:

private final AtomicReference<Node> head = new AtomicReference<>();

@SuppressWarnings("unchecked")
public void offer(final V data) {
    // create new Node
    final Node<V> newNode = new Node<>(data, Thread.currentThread().getName());
    // set root element if it's null
    if (head.compareAndSet(null, newNode)) {
        return;
    }
    // else pass trough all elements and try to set new
    Node<V> pointer = head.get();
    for (;;) {
        if (pointer.next.compareAndSet(null, newNode)) {
            break;
        }
        pointer = pointer.next.get();
    }
}

更改打印方式:

    @SuppressWarnings("unchecked")
    public void printQueueData() {
        AtomicReference<Node> pointer = head;
        while (pointer.get() != null) {
            System.out.println(pointer.get().data);
            pointer = pointer.get().next;
        }
    }