4

我已阅读有关使用同步的正确方法的类似问题的答案。但是,他们似乎没有解释为什么会出现这个问题。即使我在 getValue 和 setValue 方法中添加了同步,我仍然得到如下输出。为什么会这样?

输出:

制作套装

做得到

制作套装

做制作集

得到

做得到

制作套装

做得到

代码:

package src;

public class StackNode {
private Object value;
private StackNode next;

private final Object lock = new Object();

public StackNode() {
    setValue(null);
    setNext(null);
}

public StackNode(Object o) {
    value = 0;
    next = null;
}

public StackNode(StackNode node) {
    value = node.getValue();
    next = node.getNext();
}

public synchronized Object getValue() {
        System.out.print(" Doing ");
        System.out.println(" get ");
        System.out.flush();
        return value;

}

public  synchronized void setValue(Object value) {
        System.out.print(" making ");
        System.out.println(" set ");
        System.out.flush();
        this.value = value;
}

public synchronized StackNode getNext() {
    return next;
}

public synchronized void setNext(StackNode next) {
    this.next = next;
}
}

测试:

public class TestStackNode {
private final static StackNode node = new StackNode();

    @Test
public void getSetValueTest() throws InterruptedException{
    node.setValue("bad");
    Runnable setValue = new Runnable(){
        @Override
        public void run() {
            node.setNext(new StackNode());
            node.setValue("new");
        }
    };
    
    Runnable getValue = new Runnable(){
        @Override
        public void run() {
            Assert.assertEquals("new", node.getValue());
        }
    };
    List<Thread> set = new ArrayList<Thread> ();
    List<Thread> get = new ArrayList<Thread> ();
    for (int i = 0; i < 30000; i++){
        set.add( new Thread(setValue));
        get.add(new Thread(getValue));
    }
    
    for (int i = 0; i < 30000; i++){
        set.get(i).start();
        get.get(i).start();
    }
    
    for (int i = 0; i < 30000; i++){
        set.get(i).join();
        get.get(i).join();
    }
}
4

2 回答 2

4

这应该可以解决问题。

public Object getValue() {
  synchronized(System.out){
    System.out.print(" Doing ");
    System.out.println(" get ");
    System.out.flush();
    return value;
  }

}
于 2013-08-25T05:57:26.867 回答
2

问题是您的无参数构造函数调用setValue(...)了新创建的实例:

public StackNode() {
    setValue(null);
    setNext(null);
}

并且您Runnable setValue构造 , 的新实例StackNode以传递给node.setNext(...)

            node.setNext(new StackNode());

(即使您的测试从未实际使用node.next,所以除了它产生的输出之外,这基本上是一个无操作)。由于您的synchronized方法是实例方法(不是static方法),因此它们具有单独的锁,这意味着setValue(...)对新实例的构造函数中的调用与您在 on 上进行的调用不同步node

请注意,尽管您的具体问题相当不寻常(您有一个 getter 和 setter 正在操纵共享外部状态,即System.out,但没有任何相应的共享锁以防止干扰),但调用方法实际上总是一个坏主意来自构造函数,除非方法是privateorfinalstatic类是final,因为在子类实例完全创建之前调用超类构造函数,所以如果构造函数调用在子类中被覆盖的方法,子类方法将收到不完整的this对象并且可能行为不端。您最好将构造函数更改为:

public StackNode() {
    value = null;
    next = null;
}

(或者完全删除赋值语句,因为引用类型的字段null无论如何都会自动初始化)。

于 2013-08-25T06:35:01.120 回答