默认方法会在一段时间内返回true,然后返回false?(可能的JVM错误)


67

我的以下代码有问题,我隔离为最封闭的形式,我使用的是Java 8,该代码几乎可以启动了(2014年3月18日),因此我预计实现本身不会出现严重问题,因此可能/必须是我自己的代码:

注意:该代码是用Java 8编写的,它具有各种新功能,包括default接口中的方法实现。

public abstract class Drawable implements DrawableInterface {    

}

interface DrawableInterface {
    default public boolean isShadowReceiver() {
        return false;
    }

    default public boolean isShadowCaster() {
        return false;
    }
}

public interface ShadowDrawable extends DrawableInterface {
    @Override
    default public boolean isShadowReceiver() {
        return true;
    }

    @Override
    default public boolean isShadowCaster() {
        return true;
    }
}

public class Box extends Drawable implements ShadowDrawable {

}

public class IsolatedBug {
    private final Box box;

    private final List<Drawable> drawables;

    public IsolatedBug() {
        this.box = new Box();
        this.drawables = new ArrayList<>();

        drawables.add(box);
        drawables.forEach(drawable -> System.out.println(drawable + " C=" + drawable.isShadowCaster() + "/R=" + drawable.isShadowReceiver()));
    }

    private void init() throws InterruptedException {
        while (true) {
            drawables.forEach(drawable -> System.out.println(drawable + " C=" + drawable.isShadowCaster() + "/R=" + drawable.isShadowReceiver()));
            Thread.sleep(100);
        }
    }

    public static void main(String[] args) throws InterruptedException {
        new IsolatedBug().init();
    }
}

该代码本身可能没有多大意义,但这是因为我剥离了许多其他不相关的方法。

但是,当您观察输出时,在30秒后的某个时刻,对于我个人而言,您会看到一些奇怪的东西:

isolatedbug.Box@5acf9800 C = true / R = true
孤立的bug.Box@5acf9800 C = true / R = true
孤立的bug.Box@5acf9800 C = true / R = true
孤立的bug.Box@5acf9800 C = true / R = true
孤立的bug。 Box @ 5acf9800 C = false / R =假
isolatedbug.Box@5acf9800 C = false / R =假
isolatedbug.Box@5acf9800 C = false / R =假
isolatedbug.Box@5acf9800 C = false / R =假
isolatedbug.Box @ 5acf9800 C =错误/ R =错误
隔离错误.Box @ 5acf9800 C =错误/ R =错误

从切换true到的时间false似乎取决于该方法的调用次数,因为之间的睡眠时间较长,因此切换时间也更长。

我正在运行此程序,以获取有关Windows 8 64位的完整信息,并显示为java -version

Java版本“ 1.8.0”
Java™SE运行时环境(内部版本1.8.0-b129)
Java HotSpot(TM)64位服务器VM(内部版本25.0-b69,混合模式)

谁能告诉我发生了什么事?
我还要感谢其他使用Java 8的人(可以构建任何版本)是否可以运行并查看它们是否存在相同的问题。

使用此代码后,一些更多信息:

  Properties p = System.getProperties();
  p.list(System.out);

输出:

-- listing properties --
java.runtime.name=Java(TM) SE Runtime Environment
sun.boot.library.path=C:\Program Files\Java\jdk1.8.0\jre\bin
java.vm.version=25.0-b69
java.vm.vendor=Oracle Corporation
java.vendor.url=http://java.oracle.com/
path.separator=;
java.vm.name=Java HotSpot(TM) 64-Bit Server VM
file.encoding.pkg=sun.io
user.script=
user.country=NL
sun.java.launcher=SUN_STANDARD
sun.os.patch.level=
java.vm.specification.name=Java Virtual Machine Specification
user.dir=C:\Users\Frank\Dropbox\NetbeansProjec...
java.runtime.version=1.8.0-b129
java.awt.graphicsenv=sun.awt.Win32GraphicsEnvironment
java.endorsed.dirs=C:\Program Files\Java\jdk1.8.0\jre\li...
os.arch=amd64
java.io.tmpdir=C:\Users\Frank\AppData\Local\Temp\
line.separator=

java.vm.specification.vendor=Oracle Corporation
user.variant=
os.name=Windows 8.1
sun.jnu.encoding=Cp1252
java.library.path=C:\Program Files\Java\jdk1.8.0\bin;C:...
java.specification.name=Java Platform API Specification
java.class.version=52.0
sun.management.compiler=HotSpot 64-Bit Tiered Compilers
os.version=6.3
user.home=C:\Users\Frank
user.timezone=
java.awt.printerjob=sun.awt.windows.WPrinterJob
file.encoding=UTF-8
java.specification.version=1.8
user.name=Beheerder
java.class.path=C:\Users\Frank\Dropbox\NetbeansProjec...
java.vm.specification.version=1.8
sun.arch.data.model=64
java.home=C:\Program Files\Java\jdk1.8.0\jre
sun.java.command=isolatedbug.IsolatedBug
java.specification.vendor=Oracle Corporation
user.language=nl
awt.toolkit=sun.awt.windows.WToolkit
java.vm.info=mixed mode
java.version=1.8.0
java.ext.dirs=C:\Program Files\Java\jdk1.8.0\jre\li...
sun.boot.class.path=C:\Program Files\Java\jdk1.8.0\jre\li...
java.vendor=Oracle Corporation
file.separator=\
java.vendor.url.bug=http://bugreport.sun.com/bugreport/
sun.cpu.endian=little
sun.io.unicode.encoding=UnicodeLittle
sun.desktop=windows
sun.cpu.isalist=amd64

我还检查了-XintVM选项,使用该选项后,它会true按预期返回。

因此,结论似乎是,在我的特定用例中,代码的解释型和JIT编译/内联变体并不相同,因此,在解释型代码编译之后,它有可能从解释型转换为编译型,从而澄清了输出中的开关。

-Xint选项添加到发生错误的实际程序中,也解决了该问题。

正式的错误报告已被接受:JIRA Bug JDK-8036100


4
@Leo请阅读Java 8。
skiwi 2014年

3
是否可以进一步缩小问题的范围,例如通过删除List和new forEach,以及仅在界面中包括一种默认方法?理想情况下,它应该能够通过BuggyOverride buggy = ...; int i = 0; while (buggy.heisenbug()) i++; System.out.println("B0rked after " + i + " iterations");
amon 2014年

1
@skiwi我同意,它们应该可用。但是我认为它们并不是一个好主意。我将接口视为一种合同,当您实现自己的签名并唱歌时,即表示您同意提供自己的这些方法的实现。这些默认设置为人们打开仅在类中实现部分接口的大门,而当其他人尝试使用该类时-繁荣默认行为,而您则误以为该接口确实已实现
Mario Stoilov

11
@MarioStoilov查看Scala的“特征”。它显然是Scala最有用的功能之一。默认实现是朝这个方向迈出的一步,我已经为它们提出了很多用例。如果它们不适合,请不要使用它们。但是仅仅因为不是很有用而向别人抱怨它们。
西蒙·福斯伯格

2
@SimonAndréForsberg非常有趣-这很有意义,感谢您的例子,为队友们加油打气!
Dimitar Dimitrov 2014年

Answers:


56

这是Java8中的一个已知错误。

请参见此Jira:CHA在分析期间会忽略默认方法,从而导致错误代码生成

此博客条目启发....

更新/摘要:


以前的笔记

我用以下方法重现了此问题:

声称在b127中已解决此问题的说法令人困惑,因为我在b129中清楚地看到了它(除非我对JVM版本约定感到困惑...)

C:\Java8\jdk-1.8.0_01\bin>java -version
java version "1.8.0"
Java(TM) SE Runtime Environment (build 1.8.0-b129)
Java HotSpot(TM) 64-Bit Server VM (build 25.0-b69, mixed mode)

C:\Java8\jdk-1.8.0_01\bin>

添加System.out.println(System.getProperties());

{
java.runtime.name=Java(TM) SE Runtime Environment, 
java.runtime.version=1.8.0-b129, 
java.vm.specification.name=Java Virtual Machine Specification, 
java.vm.name=Java HotSpot(TM) 64-Bit Server VM, 
java.vm.version=25.0-b69, 
java.vm.vendor=Oracle Corporation, 
java.vendor.url=http://java.oracle.com/, 
java.vm.specification.version=1.8, 
java.specification.name=Java Platform API Specification, 
java.specification.version=1.8, 
java.specification.vendor=Oracle Corporation, 
java.class.version=52.0, 
sun.boot.library.path=C:\Java8\jdk-1.8.0_01\jre\bin, 
sun.java.launcher=SUN_STANDARD, 
sun.os.patch.level=Service Pack 1, 
java.endorsed.dirs=C:\Java8\jdk-1.8.0_01\jre\lib\endorsed, 
os.arch=amd64, 
java.vm.specification.vendor=Oracle Corporation, 
os.name=Windows 7, 
sun.jnu.encoding=Cp1252, 
java.library.path=C:\Java8\jdk-1.8.0_01\bin;......, 
sun.management.compiler=HotSpot 64-Bit Tiered Compilers, 
os.version=6.1, 
file.encoding=UTF-8, 
sun.java.command=fromso.IsolatedBug, 
java.home=C:\Java8\jdk-1.8.0_01\jre, 
sun.arch.data.model=64, 
user.language=en, 
java.ext.dirs=C:\Java8\jdk-1.8.0_01\jre\lib\ext;C:\windows\Sun\Java\lib\ext,

sun.boot.class.path=C:\Java8\jdk-1.8.0_01\jre\lib\resources.jar;......,
java.vendor=Oracle Corporation, 
file.separator=\, 
java.vendor.url.bug=http://bugreport.sun.com/bugreport/, 
sun.io.unicode.encoding=UnicodeLittle, 
sun.cpu.endian=little, 
sun.desktop=windows, 
sun.cpu.isalist=amd64
}

2
该博客文章声称该问题也已解决!修复程序将在3月发布。"UPDATE: The bug was fixed. The cause was an over optimization of the hot spot compiler. So the fix will be part of the official JDK 8 release in March! So we can use the default methods in interfaces again with not being afraid of strange behaviour."
丹·

2
@DanTemple但是博客声称,所以我宁愿有它的官方消息。
skiwi 2014年

5
@skiwi它显示为JDK-8036100,是的,它是一个P1。
ntoskrnl 2014年

5
@skiwi ...而且现在也已“修复”。不久将有一个新的版本。解决方法是禁用默认方法称为CHA的优化。JDK-8036153跟踪了对潜在问题的实际修复。
ntoskrnl 2014年

4
@skiwi我会再次被吓死。您在Java 8 GA公告(最后一段)中提到了您:mreinhold.org/blog/jdk8-ga
ntoskrnl
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.