如果值为null,我写了一个阻塞方法的小类。出于某种原因,它正在抛出一个StackOverflowError
,我做错了什么?
public class BlockingObjectProperty<T> extends SimpleObjectProperty<T> {
public T get() {
if (super.get() == null) {
addListener(((observableValue, t, t1) -> {
synchronized (this) {
notifyAll();
}
}));
synchronized (this) {
try {
wait();
} catch (InterruptedException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
}
return super.get();
}
}
这是我的测试代码:
BlockingObjectProperty<String> blockingObjectProperty = new BlockingObjectProperty<String>();
new Thread(){
public void run(){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
blockingObjectProperty.set("hello world");
}
}.start();
System.out.println(blockingObjectProperty.get());
以下是例外情况的片段:
Exception in thread "main" java.lang.StackOverflowError
at com.sun.javafx.binding.ExpressionHelper$SingleChange.<init>(ExpressionHelper.java:144)
at com.sun.javafx.binding.ExpressionHelper.addListener(ExpressionHelper.java:69)
at javafx.beans.property.ObjectPropertyBase.addListener(ObjectPropertyBase.java:87)
at com.neonorb.commons.property.BlockingObjectProperty.get(BlockingObjectProperty.java:8)
at javafx.beans.binding.ObjectExpression.getValue(ObjectExpression.java:50)
at com.sun.javafx.binding.ExpressionHelper$SingleChange.<init>(ExpressionHelper.java:152)
at com.sun.javafx.binding.ExpressionHelper$SingleChange.<init>(ExpressionHelper.java:144)
at com.sun.javafx.binding.ExpressionHelper.addListener(ExpressionHelper.java:69)
at javafx.beans.property.ObjectPropertyBase.addListener(ObjectPropertyBase.java:87)
at com.neonorb.commons.property.BlockingObjectProperty.get(BlockingObjectProperty.java:8)
at javafx.beans.binding.ObjectExpression.getValue(ObjectExpression.java:50)
at com.sun.javafx.binding.ExpressionHelper$SingleChange.<init>(ExpressionHelper.java:152)
at com.sun.javafx.binding.ExpressionHelper$SingleChange.<init>(ExpressionHelper.java:144)
at com.sun.javafx.binding.ExpressionHelper.addListener(ExpressionHelper.java:69)
at javafx.beans.property.ObjectPropertyBase.addListener(ObjectPropertyBase.java:87)
at com.neonorb.commons.property.BlockingObjectProperty.get(BlockingObjectProperty.java:8)
答案 0 :(得分:2)
当您调用addListener
时,JavaFX会询问该属性的当前值(在ExpressionHelper.java:152中),再次调用getValue()
。然后 - 因为该值仍然为null - 您无限制地添加另一个侦听器等。
答案 1 :(得分:0)
如果您想等待某个变量变为非空:
private final Object myVarLock = new Object();
private MyType myVar;
MyType get_myVar() {
synchronized(myVarLock) {
while (myVar == NULL) {
myVarLock.wait();
}
return myVar;
}
}
设置变量:
void set_myVar(myType newValue) {
synchronized(myVarLock) {
myVar = newValue;
myVarLock.notifyAll();
}
}
备注强>
getter在循环中等待。这对于严格的正确性是必要的,因为Java Langauge Spec允许wait()
返回,即使它没有得到通知。 (a.k.a。,虚假唤醒)。
即使您的JVM或应用程序中没有发生虚假唤醒,总是使用循环仍然是明智的。在多个消费者线程彼此竞争以接收事件的任何算法中,循环是必不可少的。该循环的成本不超过if
,因此您可能只是习惯于始终使用循环。
myVar的测试和myVar的分配都在synchronized
块内。这个很重要。如果他们没有同步,那么可能会发生这种情况:
线程A进入getter,测试myVar
并发现它等于NULL。
线程B进入setter,设置myVar
非空,调用myVarLock.notifyAll()
,返回。通知丢失,因为没有其他线程在等待它。
线程A调用myVarLock.wait()
并永远等待一个永远不会再发生的事件。