1

I do not understand why the race condition in the following code disappears when adding println comments. This really makes debugging hard.

How can we debug these conditions then?

In the following code the machine should throw an Exception because the two threads modify the contents of the class in an inconsistent manner.

In fact checking the code b should always be greater or equal to a (class contract). However due to the race condition between the two threads this contract is not satisfied.

Without the comments the race condition happen and the code throws an exception but with the System.out.println comments I did not get any race condition.

Java version 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(); 
        }
    }
}

Without the println message I get exception messages like:

Exception in thread "main" java.lang.Exception: b<a!!, a=104 b=27966
    at lectures.Concurrency1.checkContract(Concurrency1.java:20)
    at lectures.Concurrency1.main(Concurrency1.java:48)

Where the values are changed after the check is done... This is different from Loop doesn't see changed value without a print statement as the threads are seeing each other changes and thus generate the exception

1 Answers1

2

System.out::println contains a synchronized block which causes Threads to sequentially access the resource one by one.

From PrintStream.java

public void println(String x) {
    synchronized (this) {
        print(x);
        newLine();
    }
}

This probably acts as a filter. Multithreaded calls to your methods setRel and setEqual are first organized by System.out::println and then execute the remaining statements only one at the time.

Not sure though.

payloc91
  • 3,724
  • 1
  • 17
  • 45
  • yes I think that something like that is going on... this means that for debug conditions one should not use println... maybe the question now becomes how to debug this kind of issues? cannot give you a up vote with low reputation.. – Dimitri Ognibene Feb 16 '18 at 11:55
  • There is no need in general to use `println` in a production environment **unless** you are saving the log onto an external file. As per the development environment, the debug options (breakpoints, watchers, ...) give you all the tools you need @DimitriOgnibene – payloc91 Feb 16 '18 at 12:59
  • Also, this is a very peculiar case. I don't think the same would happen with more `Thread`s and a method with more statements... – payloc91 Feb 16 '18 at 13:09
  • yes somebody had added a solution with a sleep condition.. not exactly the same as a more complex code but... still the code here is a minimum (non)working example... – Dimitri Ognibene Feb 16 '18 at 13:13