2

Here is my code:

public class ThreadDemo {

public static void main(String args[]) throws Exception {
    Printer[] printers = new Printer[5];
    printers[0] = new Printer("@base");
    printers[1] = new Printer("#try");
    printers[2] = new Printer("!test");
    printers[3] = new Printer("^hello");
    printers[4] = new Printer("*world");

    for (Printer x : printers) {
        x.start();
    }

    try {
        for (Printer y : printers) {
            y.join();
        }
    } catch (InterruptedException e) {
        System.out.println(e);
    }
  }
}

class Printer extends Thread {
public Printer(String name) {
    super(name);
}

public void run() {
    print();
}

public synchronized void print() {
    for (int i = 0; i < 10; i++) {
        System.out.print(getName().charAt(0));
        try {
            sleep(100);
        } catch (InterruptedException e) {
            System.out.println(e + " occured");
        }
    }
  }
}

It results in

@^!#**@^!#*#@!^@*#^!#^!*@^*@!#@!#*^@#^!*!@^#*#@*^! 

My expectation is that all symbols would be serialized as @@@@@^^^^^ based on which thread starts first.

Calling sleep() would let other threads to proceed until sleeptime of current thread , but i guess that should not be the case with synchronized method.

GhostCat
  • 137,827
  • 25
  • 176
  • 248
Sundar Rajan
  • 556
  • 4
  • 25

3 Answers3

6

The synchronised doesn't come into play here.

That keyword makes sure that you can't invoke the same method on the same object in parallel.

You are invoking it on different objects, therefore the result would be the same even without the keyword in place!

( I rather assume that the result you see is in fact caused by using println() here. That is a "really slow" operation that introduces "de facto" synchronisation when used by threads that are super-quick doing all their other work. I am trying to find some additional information about that, but that might take some more time )

GhostCat
  • 137,827
  • 25
  • 176
  • 248
  • Is it related to this thread https://stackoverflow.com/questions/9459657/synchronization-and-system-out-println – Sundar Rajan Aug 07 '18 at 18:17
  • If println() is slow for thread , what is the alternative - BufferedWriter ? – Sundar Rajan Aug 07 '18 at 18:18
  • 1
    A) probably yes B) you could try to *not* print while the threads are running. Instead, have a `static synchronized void append()` method that takes chars and appends them to a StringBuilder for example. Then, when all threads are done, print the content of that StringBuilder. On top of that, you could *vary* the sleep time, make it random to a certain degree for example. It really depends what you "want" to see here. – GhostCat Aug 07 '18 at 18:25
  • @GhostCat "Same method?" Maybe in this case, but that's because only one method is `synchronized` here. The normal description of that keyword would be something like, "The JVM will never allow more than one thread to be `synchronized` on the same object at the same time." The identity of any particular `synchronized` method or `synchronized` block doesn't enter in to it at all. – Solomon Slow Aug 07 '18 at 20:10
  • @SolomonSlow - So it has to be corrected as 'No Synchronized methods' can be called on the same object at same time ? – Sundar Rajan Feb 05 '19 at 13:32
1

The issue with your code or I would say your expectation is that the method print is synchronized at the object level and you are creating new thread objects, starting the thread and calling this method.

So in this case, each method is synchronized on each individual thread object. To achieve the behavior you expect, we can make the print method static and see the behavior change. You will get the expected result because then, the method print is synchronized on a single instance of Printer class lock. So even if different threads instance are calling this method, because there is a single lock for class, thread execution happens sequentially.

public static synchronized void print() {
    for (int i = 0; i < 10; i++) {
        System.out.print(Thread.currentThread().getName().charAt(0));
        try {
            sleep(100);
        } catch (InterruptedException e) {
            System.out.println(e + " occured");
        }
    }

}
Ashishkumar Singh
  • 3,580
  • 1
  • 23
  • 41
  • That works, but it only works because a `ThreadDemo` instance has no state that the `print()` method needs to access. In many practical classses, you would not be able to solve the problem in that way. – Solomon Slow Aug 07 '18 at 20:23
1

@SolomonSlow - So it has to be corrected as 'No Synchronized methods' can be called on the same object at same time ?

There is only one thing you will ever need to know about a synchronized instance method. You need to know that this...

synchronized void Foobar() { ... }

...Is just a shortcut way of writing a synchronized block.

void Foobar() {
    synchronized (this) {
        ...
    }
}

Both of those method declarations do exactly the same thing. So, everything you know or learn about how synchronized blocks behave can be applied to synchronized methods too.

The most important thing to know about synchronized blocks is, "No two threads can ever be synchronized on the same object at the same time." If you understand that, and if you know how a synchronized method is just a shortcut for a synchronized block, then you can answer your own question.

Solomon Slow
  • 25,130
  • 5
  • 37
  • 57