Java 8 中的可能错误 Windows 8 上的更新 45

Possible bug in Java 8 Update 45 on Windows 8

此代码采用输入图像并生成尺寸两倍大的输出图像。内循环中的前四行写了四个相同大小的原始副本,最后四行应该用输入图像的一个副本覆盖小图像,该副本是原始图像的两倍。

代码在 Java 8 上编译和运行没有错误,在 Windows 8 上更新 45。结果图像不是预期的输入的一大副本。输出的下半部分符合预期,但上半部分由循环内前两行写入的输入的两个原始大小的副本组成。注释掉这两行会导致最初预期的结果,因此前两行似乎是最后执行的,而不是最先执行的,尽管在源代码中最先出现。

这是编译器错误、运行时竞争条件还是代表我的脑放屁?

如果需要,我会在某处提供示例。

import java.awt.image.*;
import java.io.*;
import javax.imageio.*;
class HelloWorldApp {
    public static void main(String[] orgs) throws IOException {

        BufferedImage pic = ImageIO.read(new File("cat.jpg"));

        int w=pic.getWidth(),h=pic.getHeight();
        BufferedImage out = new BufferedImage(w+w,h+h,pic.getType());
        for (int y=0;y<h;y++) {
            for (int x=0;x<w;x++) {
                int pixel = pic.getRGB(x,y);
                // write four small copies
                out.setRGB(x    ,y    ,pixel); // these two lines apparently are
                out.setRGB(x+w  ,y    ,pixel); // executed after the remaining six
                out.setRGB(x    ,y+h  ,pixel);
                out.setRGB(x+w  ,y+h  ,pixel);
                // overwrite with one large copy
                out.setRGB(x+x  ,y+y  ,pixel);
                out.setRGB(x+x+1,y+y  ,pixel);
                out.setRGB(x+x  ,y+y+1,pixel);
                out.setRGB(x+x+1,y+y+1,pixel);
            }
        }

        ImageIO.write(out, "bmp", new File("./cat.bmp"));

    }
}

恐怕这是一个脑放屁。因为您在同一个循环中执行所有操作,所以在后面的迭代中执行最初的四行(小副本)最终会覆盖在前面的迭代中由最后四行(大副本)写入的像素。

我不确定我的措辞是否出色,但希望您能明白我的意思。

让我们尝试演示发生了什么。假设您的图像是:

┌───╥───┬───┐
│   ║ 0 │ 1 │
╞═══╬═══╪═══╡
│ 0 ║ A │ B │
├───╫───┼───┤
│ 1 ║ C │ D │
└───╨───┴───┘

对于x=0,y=0,前四行后:

┌───╥───┬───┬───┬───┐
│   ║ 0 │ 1 │ 2 │ 3 │
╞═══╬═══╪═══╪═══╪═══╡
│ 0 ║ A │   │ A │   │
├───╫───┼───┼───┼───┤
│ 1 ║   │   │   │   │
├───╫───┼───┼───┼───┤
│ 2 ║ A │   │ A │   │
├───╫───┼───┼───┼───┤
│ 3 ║   │   │   │   │
└───╨───┴───┴───┴───┘

最后四行之后:

┌───╥───┬───┬───┬───┐
│   ║ 0 │ 1 │ 2 │ 3 │
╞═══╬═══╪═══╪═══╪═══╡
│ 0 ║ A │ A │ A │   │
├───╫───┼───┼───┼───┤
│ 1 ║ A │ A │   │   │
├───╫───┼───┼───┼───┤
│ 2 ║ A │   │ A │   │
├───╫───┼───┼───┼───┤
│ 3 ║   │   │   │   │
└───╨───┴───┴───┴───┘

对于 x=1,y=0,在前四行之后:

┌───╥───┬───┬───┬───┐
│   ║ 0 │ 1 │ 2 │ 3 │
╞═══╬═══╪═══╪═══╪═══╡
│ 0 ║ A │ B │ A │ B │
├───╫───┼───┼───┼───┤
│ 1 ║ A │ A │   │   │
├───╫───┼───┼───┼───┤
│ 2 ║ A │ B │ A │ B │
├───╫───┼───┼───┼───┤
│ 3 ║   │   │   │   │
└───╨───┴───┴───┴───┘

最后四行之后:

┌───╥───┬───┬───┬───┐
│   ║ 0 │ 1 │ 2 │ 3 │
╞═══╬═══╪═══╪═══╪═══╡
│ 0 ║ A │ B │ B │ B │
├───╫───┼───┼───┼───┤
│ 1 ║ A │ A │ B │ B │
├───╫───┼───┼───┼───┤
│ 2 ║ A │ B │ A │ B │
├───╫───┼───┼───┼───┤
│ 3 ║   │   │   │   │
└───╨───┴───┴───┴───┘

对于 x = 0,y = 1,前四行:

┌───╥───┬───┬───┬───┐
│   ║ 0 │ 1 │ 2 │ 3 │
╞═══╬═══╪═══╪═══╪═══╡
│ 0 ║ A │ B │ B │ B │
├───╫───┼───┼───┼───┤
│ 1 ║ C │ A │ C │ B │
├───╫───┼───┼───┼───┤
│ 2 ║ A │ B │ A │ B │
├───╫───┼───┼───┼───┤
│ 3 ║ C │   │ C │   │
└───╨───┴───┴───┴───┘

最后四行:

┌───╥───┬───┬───┬───┐
│   ║ 0 │ 1 │ 2 │ 3 │
╞═══╬═══╪═══╪═══╪═══╡
│ 0 ║ A │ B │ B │ B │
├───╫───┼───┼───┼───┤
│ 1 ║ C │ A │ C │ B │
├───╫───┼───┼───┼───┤
│ 2 ║ C │ C │ A │ B │
├───╫───┼───┼───┼───┤
│ 3 ║ C │ C │ C │   │
└───╨───┴───┴───┴───┘

对于 x=1,y=1,前四行:

┌───╥───┬───┬───┬───┐
│   ║ 0 │ 1 │ 2 │ 3 │
╞═══╬═══╪═══╪═══╪═══╡
│ 0 ║ A │ B │ B │ B │
├───╫───┼───┼───┼───┤
│ 1 ║ C │ D │ C │ D │
├───╫───┼───┼───┼───┤
│ 2 ║ C │ C │ A │ B │
├───╫───┼───┼───┼───┤
│ 3 ║ C │ D │ C │ D │
└───╨───┴───┴───┴───┘

最后四行:

┌───╥───┬───┬───┬───┐
│   ║ 0 │ 1 │ 2 │ 3 │
╞═══╬═══╪═══╪═══╪═══╡
│ 0 ║ A │ B │ B │ B │
├───╫───┼───┼───┼───┤
│ 1 ║ C │ D │ C │ D │
├───╫───┼───┼───┼───┤
│ 2 ║ C │ C │ D │ D │
├───╫───┼───┼───┼───┤
│ 3 ║ C │ D │ D │ D │
└───╨───┴───┴───┴───┘

这不是您预期的结果,它源于这样一个事实,即在每次迭代中,您返回并覆盖四个像素。其中一些像素属于您的双像。

发生的情况是,小图像是同时从顶部和中间开始逐行写入的。大图也是从顶部开始,但是 "moves" 快了一倍。因此,上半部分的小 "slow" 图像覆盖了较早写入的快速大像素,而在下半部分,已经写入的 "small" 像素被稍后到达的快速前沿覆盖。

我上传了一个 animation on YouTube 显示过程。

(Phil 和 RealSkeptic 的回答都有助于找到解释。我选择 Phil 的回答是因为他的回答更接近于解释到底发生了什么。)