Java 插入System.out.println调用会影响竞争条件:如何调试?

Java 插入System.out.println调用会影响竞争条件:如何调试?,java,multithreading,debugging,synchronization,race-condition,Java,Multithreading,Debugging,Synchronization,Race Condition,我不明白为什么在添加println注释时,下面代码中的竞争条件消失了。 这确实使调试变得困难。 那么我们如何调试这些条件呢? 在下面的代码中,机器应该抛出异常,因为两个线程以不一致的方式修改类的内容 事实上,检查代码b应该总是大于或等于a(类契约)。然而,由于两个线程之间的竞争条件,本合同不满足 如果没有注释,竞争条件就会发生,代码会抛出异常,但是使用System.out.println注释,我没有得到任何竞争条件 Java版本1.8.0_112 package lectures; impor

我不明白为什么在添加println注释时,下面代码中的竞争条件消失了。 这确实使调试变得困难。

那么我们如何调试这些条件呢?

在下面的代码中,机器应该抛出异常,因为两个线程以不一致的方式修改类的内容

事实上,检查代码b应该总是大于或等于a(类契约)。然而,由于两个线程之间的竞争条件,本合同不满足

如果没有注释,竞争条件就会发生,代码会抛出异常,但是使用System.out.println注释,我没有得到任何竞争条件

Java版本1.8.0_112

package lectures;

import java.util.Random;

public class Concurrency1 {
    int a,b;
    void setEqual(int x){
//      System.out.println("setEqual "+x);
        a=x;
        b=x;
    }

    void setRel(){
//      System.out.println("setRel");
        a++;
        b+=a;
    }

    void checkContract() throws Exception{
        if (b<a) throw new Exception("b<a!!, a="+a+" b="+b); 
    }

    public static void main(String[] args) throws Exception{
        Concurrency1 c1=new Concurrency1();
        final  int count=10000000;
        Thread t1=new Thread(){
            public void run(){
                Random gen=new Random();
                int c=0;
                while(c++<count){
                    System.out.println("setEqual ");
                    c1.setEqual(gen.nextInt(10));
                }
        }};
        Thread t2=new Thread(){
            public void run(){
                int c=0;
                while(c++<count){
                    System.out.println("setGen ");
                    c1.setRel();
                }
        }};
        t1.start();
        t2.start();
        int c=0;
        while(t1.isAlive()||t2.isAlive()||c++<count){
            c1.checkContract(); 
        }
    }
}
套餐讲座;
导入java.util.Random;
公共类并发1{
INTA,b;
void setEqual(int x){
//System.out.println(“setEqual”+x);
a=x;
b=x;
}
void setRel(){
//系统输出打印项次(“setRel”);
a++;
b+=a;
}
void checkContract()引发异常{

如果(b)线程看到彼此发生变化,从而生成异常,则系统输出::println
包含一个
同步的
块,该块导致
线程逐个顺序访问资源

PrintStream.java

public void println(String x) {
    synchronized (this) {
        print(x);
        newLine();
    }
}
这可能充当一个过滤器。对方法
setRel
setEqual
的多线程调用首先由
System.out::println
组织,然后只执行一个剩余语句


但不确定。

值会发生更改,如异常thrownYes所示。众所周知,争用条件很难调试。在调试器中单步执行代码会使它们“消失”,即使您登录到特定于线程的非同步缓冲区,计时也可能会改变,您将不再看到竞争。@raedwald您的评论已经被提及。是的,我认为类似的情况正在发生……这意味着在调试条件下不应使用println……现在的问题可能是如何调试这种issues?不能以低信誉向您投赞成票。除非您将日志保存到外部文件中,否则通常不需要在生产环境中使用
println
。根据开发环境,调试选项(断点、观察者等)给你所有你需要的工具@dimitriognibene同样,这是一个非常特殊的情况。我不认为更多的
线程和包含更多语句的方法会发生同样的情况…是的,有人添加了一个带有睡眠条件的解决方案…与更复杂的代码不完全相同,但…这里的代码仍然是最小值(非)工作示例。。。
public void println(String x) {
    synchronized (this) {
        print(x);
        newLine();
    }
}