0

我正在学习并发编程,并使用AtomicReference编写了这个concurrentLinkeQueue。ConcurrentLinkQueue执行进入死锁

下面的例子进入死锁。请参见。

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 

可以请你帮忙,为什么线程等待永远在这里永远等下去?

[编辑] 解决了这个问题--->

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(); 
     } 
    } 
} 

}

另一个解决方案 - >

 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(); 
    } 
} 
+0

在它卡住之前它通过循环多少次? – tbodt

+0

只有1个线程第一次成功休眠死锁。和线程谁第二次成功Stuart第二次 – HakunaMatata

+1

我不认为这个代码是线程安全的,我怀疑两个线程进入'如果'具有相同的'头',然后碰巧'next'不再指向'null' - 如此无限循环...如果你想以原子方式执行多个操作,你需要同步。 –

回答

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; 
     } 
    } 
+0

你的程序似乎是正确的,我修改了它,并且它的工作正常。这是对的吗 ? public void fastOffer(final V data){ final Node newNode = new Node (data,Thread.currentThread()。getName()); System.out.println(newNode); AtomicReference pointer = firstNodePointer; (;;){ if(pointer.get()== null){ if(pointer.compareAndSet(null,newNode)){ return; } } pointer = pointer.get()。getNext(); } } – HakunaMatata

+0

是的,但我认为条件'如果(指针。get()== null)'不一定是因为下一个'compareAndSet'做同样的事情。 – aim