4

I'm reading Java The Complete Reference(9th Edition) after year of fooling around with Java. Been happy with the book so far but I now have a really strange problem with synchronized threads:

package syncro;

class Callme {
    void call(String msg) {
        System.out.print("[" + msg);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            System.out.println("Interrupted");
        }
        System.out.println("]");
    }
}

class Caller1 implements Runnable {
    String msg;
    Callme target;
    Thread t;

    public Caller1(Callme targ, String s) {
        target = targ;
        msg = s;
        t = new Thread(this);
        t.start();
    }

    @Override
    public void run() {
        synchronized (target) { // SYNC BLOCK
            target.call(msg);
        }

    }
}

public class Syncronized {
    public static void main(String[] args) {
        Callme target = new Callme();
        Caller1 ob1 = new Caller1(target, "Hello");
        Caller1 ob2 = new Caller1(target, "Synchronized");
        Caller1 ob3 = new Caller1(target, "World");

        try {
            ob1.t.join();
            ob2.t.join();
            ob3.t.join();
        } catch (InterruptedException e) {
            System.out.println("Interrupted");
        }
    }

}

It prints out:

[Hello]
[World]
[Synchronized]

and I don't understand how that's even possible. Also worth mentioning, if I swap the lines

 Caller1 ob2 = new Caller1(target, "Synchronized");
 Caller1 ob3 = new Caller1(target, "World");

(constructor is called with the string "World" before "Synchronized") it will print

[Hello]
[Synchronized]
[World]

as I would have expected in the first place.

I didn't find a question like this here so I hope I'm doing this right... Thanks!

1
  • 1
    The order in which threads execute is determined by the JVM and does not need to be the same as the order in which they are defined. In other words, thread execution order is undefined. If you want threads to execute in a particular order or have their execution depend on other threads, then you will need to perform thread synchronization. There are high level abstractions in java.lang.concurrent that were designed for this purpose, eg. CountDownLatch. Commented Apr 20, 2015 at 23:06

3 Answers 3

4

The short answer is that the only thing your synchronized block guarantees is that your 3 calls to Callme.call will be mutually exclusive - you won't (for example) end up with all 3 of your threads in the Thread.sleep call simultaneously. It doesn't guarantee anything about the order in which the three calls will occur, and in fact it would be possible (though unlikely) that running your unmodified code multiple times could result in your 3 words being output in any order on any particular run.

Sign up to request clarification or add additional context in comments.

1 Comment

Okay looks like I misunderstood the whole thing then! Thanks for the response!
1

When you start multiple threads they all need some time to spin up, java does not garantee in which order this completes. The first thread which reaches the call() method will execute it, then the next. There is nothing in your code which enforces a sequence of that.

1 Comment

Oh! Interesting. That explains it. Thanks for the answer
1

When multiple threads are waiting on a lock, there is no guarantee as to which thread the lock will be given once its released. The docs does not specify how this order is handled, but its also not random. I cant say for certain, but it seems the default implementation gives the lock in a LIFO style (Last in first out) and thats why world is outputted first. Give it a try with some more objects.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.