4

I was learning multithreading in java, In the tutorial, it said removing synchronized should make the program buggy and it did, So I was just experimenting around and wrote a print line System.out.println(Thread.currentThread().getName() + " " +count); and removed the synchronized word, and even then the program worked fine. But if only synchronized word is removed and the printline(System.out.println(Thread.currentThread().getName() + " " +count);) is not added the program is buggy ad expected.

I can't understand how adding a print line can make it synchronized.

public class intro implements Runnable {

    int n=10000; 
    private int count = 0; 

    public int getCount() { return count; }

    public synchronized void incrSync() { count++;  }

    public void run () {
        for (int i=0; i<n; i++) {
            incrSync();
            //System.out.println(Thread.currentThread().getName() + "  " +count);       
        } 
        } 


    public static void main(String [] args) {

        intro mtc = new intro();
        Thread t1 = new Thread(mtc);
        Thread t2 = new Thread(mtc);
        t1.start();
        t2.start();
        try {
            t1.join();

            t2.join();

        } catch (InterruptedException ie) {
        System.out.println(ie);
        ie.printStackTrace();
    }
    System.out.println("count = "+ mtc.getCount());
}
}
4rshdeep
  • 490
  • 4
  • 11
  • 3
    println() is synchronized. So it causes threads to acquire and release a lock. You should of course not rely on that to make your code thread-safe. – JB Nizet May 25 '17 at 06:43
  • @JBNizet I can't find a reference to that, can you please provide one? I checked the Java docs and https://stackoverflow.com/a/9459886 – 11thdimension May 25 '17 at 06:49
  • The javadoc doesn't mention if a method (or its internal code) is synchronized. That's an implementation detail, that isn't part of the API. But the source code of PrintStream comes with the JDK. Just look at it. – JB Nizet May 25 '17 at 06:52
  • I will check that, however that shouldn't synchronize the `println` caller method. – 11thdimension May 25 '17 at 06:55
  • 3
    It doesn't. But it makes a race condition less likely to happen, making the program **look** safe (when it's not). – JB Nizet May 25 '17 at 06:58
  • 1
    Also remember that in some situations (such as double-checked locking) having a synchronized method is not enough; you also have to make the variable `volatile`. (See https://en.wikipedia.org/wiki/Double-checked_locking#Usage_in_Java for the explanation of the gory details.) – Klitos Kyriacou May 25 '17 at 07:02
  • @JBNizet exactly what I was thinking, I was going to add more code to the run to make it more unstable, as with the provided code `println` doesn't let it go out of sync even for 9 digit values for `n` – 11thdimension May 25 '17 at 08:25
  • @KlitosKyriacou, Great link. Do you know if this is true for locks or not ? – 11thdimension May 25 '17 at 08:39

2 Answers2

3

Synchronization issues happen between threads when multiple threads attempt access to the same field at the same time.

Without the printing the run method sits in a tight loop accessing the counter almost continuously. Making multiple threads do that without synchronization is very likely to cause a fault.

By adding the printing you are changing the loop to spend most (almost all) of its time printing and only occasionally increment the count. This is much less likely to cause contention.

The code is still buggy with the printing, the only difference is that the contention will happen much less often and your test of just 1000 loops is not sufficient to demonstrate the issue. You'd probably have to run it for a few years before the threads clashed.

This is a classic demonstration of why threading issues are so difficult to find and fix. That loop (with it's print statement) could run on multiple threads for years without contention but if just one clash between threads happens then the code breaks. Imagine that happening in a heart pacemaker or a satellite or a nuclear power station!

OldCurmudgeon
  • 64,482
  • 16
  • 119
  • 213
0

The println method calls newline, which is a method with a synchronized-block. It is giving correct result, though it is not thread safe.

Consider T1 read count 5 and T2 read count 5 simultaneously, then race condition happen. It is giving correct result because you are using System.out.println(Thread.currentThread().getName() + " " +count); which is blocking. Increase thread number.

 private void newLine() {
    try {
        synchronized (this) {
            ensureOpen();
            textOut.newLine();
            textOut.flushBuffer();
            charOut.flushBuffer();
            if (autoFlush)
                out.flush();
        }
    }
    catch (InterruptedIOException x) {
        Thread.currentThread().interrupt();
    }
    catch (IOException x) {
        trouble = true;
    }
}
Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
gati sahu
  • 2,576
  • 2
  • 10
  • 16
  • 1
    although it's synchorized, but i try make the 'n' bigger( such as 1000000),it still dont sum up the right number(1999992) – herokingsley May 26 '17 at 03:46