[英]How to choose what object to lock on in Java?
我已经阅读了有关使用synchronized的正确方法的类似问题的答案。 但是,他们似乎没有解释为什么会出现这个问题。 即使我将synchronized添加到我的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();
}
}
这应该解决问题。
public Object getValue() {
synchronized(System.out){
System.out.print(" Doing ");
System.out.println(" get ");
System.out.flush();
return value;
}
}
问题是你的no-arg构造函数在新创建的实例上调用setValue(...)
:
public StackNode() {
setValue(null);
setNext(null);
}
并且您的Runnable setValue
构造一个新的StackNode
实例,以传递给node.setNext(...)
:
node.setNext(new StackNode());
(即使你的测试从未真正使用过node.next
,所以除了它产生的输出之外,这实际上是一个无操作)。 由于您的synchronized
方法是实例方法(不是static
方法),因此它们具有单独的锁,这意味着在新实例的构造函数中对setValue(...)
的调用与您在node
上进行的调用不同步。
请注意,虽然您的特定问题相当罕见(您有一个getter和setter正在操作共享外部状态,即System.out
,但没有任何相应的共享锁来防止干扰),实际上总是一个坏主意从构造函数调用方法,除非该方法是private
或final
或static
或者类是final
,因为在完全创建子类实例之前调用超类构造函数,因此如果构造函数调用在子类中重写的方法,子类方法将收到一个不完整的this
对象,并可能行为异常严重。 你最好将构造函数更改为:
public StackNode() {
value = null;
next = null;
}
(或者只是完全删除赋值语句,因为引用类型的字段无论如何都会自动初始化为null
)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.