Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 奇怪的种族状况?_Java_Multithreading_Race Condition - Fatal编程技术网

Java 奇怪的种族状况?

Java 奇怪的种族状况?,java,multithreading,race-condition,Java,Multithreading,Race Condition,我写的方法有问题。它所做的是等待一个属性等于另一个值。我不能在这里复制它,但是在我正在运行的单元测试中,我想等待一个特定的值为真。它先打印“等待”,然后打印“通知”(表示它应该正常工作),但永远不会打印“完成等待”。它并不总是这样,有时它工作得完美无缺,这就是为什么我认为这是某种比赛条件 我以前使用过锁定API,但也遇到了同样的问题,所以我决定尝试旧的wait/notify方法 在它有机会等待之前,它可能是正在创建和调用的侦听器吗?即使这是问题所在,也不应该先打印“等待”,然后再打印“通知”。即

我写的方法有问题。它所做的是等待一个属性等于另一个值。我不能在这里复制它,但是在我正在运行的单元测试中,我想等待一个特定的值为真。它先打印“等待”,然后打印“通知”(表示它应该正常工作),但永远不会打印“完成等待”。它并不总是这样,有时它工作得完美无缺,这就是为什么我认为这是某种比赛条件

我以前使用过锁定API,但也遇到了同样的问题,所以我决定尝试旧的wait/notify方法

在它有机会等待之前,它可能是正在创建和调用的侦听器吗?即使这是问题所在,也不应该先打印“等待”,然后再打印“通知”。即使我在“等待”和“通知”时打印ms,等待仍然在通知之前

private static <T> void waitFor(ObservableValue<T> value, T wantedValue) throws InterruptedException {
    if (value.getValue() != wantedValue) {
        Object lock = new Object();
        synchronized (lock) {
            value.addListener((observableValue, t, t1) -> {
                if (value.getValue() != wantedValue) {
                    return;
                }
                synchronized (lock) {
                    System.out.print("notify");
                    lock.notifyAll();
                }
            });
            System.out.println("wait");
            lock.wait();
            System.out.println("done waiting");
        }
    }
}
private static void waitFor(ObservalEvalue值,T wantedValue)抛出InterruptedException{
if(value.getValue()!=wantedValue){
对象锁=新对象();
已同步(锁定){
value.addListener((observeValue,t,t1)->{
if(value.getValue()!=wantedValue){
返回;
}
已同步(锁定){
系统输出打印(“通知”);
lock.notifyAll();
}
});
System.out.println(“等待”);
lock.wait();
System.out.println(“完成等待”);
}
}
}
没有道理

多个线程必须使用同一对象在上进行同步,否则同步将无法进行

最后,您的代码一直在等待一个信号,因为该对象是该方法的本地对象,所以其他线程都无法向
lock
对象发送该信号

编辑:请忽略以上内容。这只是因为我忽略了锁对象被传递给匿名监听器,而匿名监听器是从方法中传递出来的

然而,另一个潜在的竞争条件正在发生

if (value.getValue() != wantedValue) {
    Object lock = new Object();
    synchronized (lock) { ...
如果值在执行
getValue()
之后但在执行
value.addListener(…)
之前异步更改,该怎么办

还有另一个小问题:for
wait()
声明“可能出现虚假唤醒,此方法应始终在循环中使用”(强调我的方法)

没有道理

多个线程必须使用同一对象在上进行同步,否则同步将无法进行

最后,您的代码一直在等待一个信号,因为该对象是该方法的本地对象,所以其他线程都无法向
lock
对象发送该信号

编辑:请忽略以上内容。这只是因为我忽略了锁对象被传递给匿名监听器,而匿名监听器是从方法中传递出来的

然而,另一个潜在的竞争条件正在发生

if (value.getValue() != wantedValue) {
    Object lock = new Object();
    synchronized (lock) { ...
如果值在执行
getValue()
之后但在执行
value.addListener(…)
之前异步更改,该怎么办


还有另一个小问题:for
wait()
声明“虚假唤醒是可能的,此方法应始终在循环中使用”(强调我的)。

到目前为止关于锁的评论忽略了一个重要的细节。锁变量实际上不是局部变量。它在Java8中是“有效的最终”,因为它在侦听器闭包中被引用。这意味着它实际上被复制到实现closure对象的匿名类中的一个特殊编译器生成的字段中,因此,它实际上可能在调用waitFor()的线程和调用注册侦听器闭包的任何线程之间共享。所以,我认为这根本不是问题所在

然而,根据您期望发生的情况,代码中可能存在竞争条件。在调用wait()之前添加了侦听器,这意味着如果在您可以访问wait()之前有一个即时异步通知,侦听器对notifyAll()的调用将丢失,代码将永远等待已经发生的通知。当然,如果您希望将来有更多的通知,这并不是一个真正的问题,因为当下一个通知出现时,您将取消阻止,但是我希望您在单元测试中看到这个错误,在单元测试中,您只等待一个通知,有时您只是错过了它,这有时会导致测试失败

还有一个想法。也许您可以将代码更改为:

ObservableValue.waitFor(T值)


没有static关键字的代码几乎总是更好的(我希望它不存在)。如果ObservalEvalue是一个接口,那么您始终可以将waitFor()作为默认方法,因为您使用的是Java 8。

到目前为止关于锁的评论忽略了一个重要的细节。锁变量实际上不是局部变量。它在Java8中是“有效的最终”,因为它在侦听器闭包中被引用。这意味着它实际上被复制到实现closure对象的匿名类中的一个特殊编译器生成的字段中,因此,它实际上可能在调用waitFor()的线程和调用注册侦听器闭包的任何线程之间共享。所以,我认为这根本不是问题所在

然而,根据您期望发生的情况,代码中可能存在竞争条件。在调用wait()之前添加了侦听器,这意味着如果在您可以访问wait()之前有一个即时异步通知,侦听器对notifyAll()的调用将丢失,代码将永远等待已经发生的通知。当然,如果您希望将来有更多的通知,这其实不是问题,因为您将在下一个通知出现时解除阻止,但是