Java中非常奇怪的线程错误

Java中非常奇怪的线程错误,java,multithreading,Java,Multithreading,我已经写了一篇文章,专门用来截图并将其转换成jpg。因此,我的另一个线程可以在拍摄下一个屏幕截图时将此屏幕截图并行发送到另一台计算机。到现在为止,一直都还不错。直到我添加了一个System.out.println之后,才开始拍摄新的屏幕截图。。。截图准备好了。。。这真的很奇怪,因为println不应该影响线程 你能解释一下为什么它只适用于这个system.out.println吗 public void run(){ while(continueLoop){ System

我已经写了一篇文章,专门用来截图并将其转换成jpg。因此,我的另一个线程可以在拍摄下一个屏幕截图时将此屏幕截图并行发送到另一台计算机。到现在为止,一直都还不错。直到我添加了一个System.out.println之后,才开始拍摄新的屏幕截图。。。截图准备好了。。。这真的很奇怪,因为println不应该影响线程

你能解释一下为什么它只适用于这个system.out.println吗

public void run(){
    while(continueLoop){
        System.out.println("screenshot_ready: " + screenshot_ready + "\n");
        if(!screenshot_ready){
            try {
                temp = getImageAsJPEG(robot.createScreenCapture(rectangle));
                screenshot_ready = true;
                System.out.println("screenshot created");
            } catch (ImageFormatException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

public byte[] returnJPG() {
    screenshot_ready = false;
    return temp;
}

正如评论中所说,如果使用多个线程而没有正确的线程安全结构,可能会导致意外行为,包括在某些情况下运行时可能没有可见错误

在您的例子中,是
System.out
打印流内部的同步对编写线程(创建屏幕截图的线程)产生了副作用,使程序看起来像是在做您想要做的事情

然而,由于不清楚是什么让读取线程看起来做了正确的事情,整个程序运行起来就很困难。哪怕是一点点变化都可能使它破裂。而且更改甚至不需要在您的程序中

由于您的程序旨在将数据从一个线程转移到另一个线程,因此
SynchronousQueue
将是一个不错的选择。与实际队列不同,它的行为类似于双线程场景中的一个简单变量。但是作为一个
阻塞队列
,它也解决了程序的其他缺陷,比如在CPU消耗循环中轮询变量,或者可能多次编写相同的屏幕截图

final SynchronousQueue<byte[]> data=new SynchronousQueue<>();

public void run(){
  while(continueLoop) try {
    data.put(getImageAsJPEG(robot.createScreenCapture(rectangle)));
    } catch (ImageFormatException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (InterruptedException ex) {
        if(continueLoop) ex.printStackTrace();
    }
}

public byte[] returnJPG() throws InterruptedException {
    return data.take();
}
final SynchronousQueue data=new SynchronousQueue();
公开募捐{
尽管(继续)尝试{
data.put(getImageAsJPEG(robot.createScreenCapture(矩形));
}捕获(ImageFormat异常){
e、 printStackTrace();
}捕获(IOE异常){
e、 printStackTrace();
}捕获(中断异常例外){
if(continueLoop)例如printStackTrace();
}
}
公共字节[]returnJPG()引发InterruptedException{
返回数据。take();
}

我看不到任何同步。很可能是
println
正在改变计时和/或内存顺序,使其恰好工作。
screenhotu准备好了吗
易失性?我敢打赌这是一个同步问题,但是你没有显示另一个线程的代码。你需要考虑内存顺序和同步,尽管很多代码构造都处理这两个线程。你必须假设一个线程可能有它自己的,可能过期的,它所使用的任何数据的副本,除非你已经做了一些事情来确保它有当前的数据。@Felix use@Felix几乎可以肯定有一个bug,它在你的代码中。您有多个共享变量的线程,但没有同步。添加打印语句时,行为会发生变化,因为这会影响线程切换的计时。我建议您在代码中添加适当的同步。