Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multithreading: Why this output? Is it deterministic?

I'm learning to write better multi-threaded programs, thread-safe and deterministic. I came across this piece of code

// File Name : Callme.java
// This program uses a synchronized block.
  class Callme {
     void call(String msg) {
        System.out.print("[" + msg);
        try {
           Thread.sleep(1000);
        } catch (InterruptedException e) {
           System.out.println("Interrupted");
        }
        System.out.println("]");
     }
  }

  // File Name : Caller.java
  class Caller implements Runnable {
     String msg;
     Callme target;
     Thread t;
     public Caller(Callme targ, String s) {
        target = targ;
        msg = s;
        t = new Thread(this);
        t.start();
     }

     // synchronize calls to call()
     public void run() {
        synchronized(target) { // synchronized block
           target.call(msg);
        }
     }
  }
  // File Name : Synch.java
  public class Synch {
     public static void main(String args[]) {
        Callme target = new Callme();
        Caller ob1 = new Caller(target, "Hello");
        Caller ob2 = new Caller(target, "Synchronized");
        Caller ob3 = new Caller(target, "World");

        // wait for threads to end
        try {
           ob1.t.join();
           ob2.t.join();
           ob3.t.join();
        } catch(InterruptedException e) {
           System.out.println("Interrupted");
        }
     }
  }

which produces the following output(tried it ~100 times)

[Hello]
[World]
[Synchronized]

So my first question is, is this output guaranteed? I also observed that if I change sleep to 100 it still produces the same output, but if I change sleep to 10 the output changes to

[Hello]
[Synchronized]
[World]

Second question is, If it's guaranteed, why? Last but not the least, Why this output? I expected it to be

[Hello]
[Synchronized]
[World]
like image 378
vidit Avatar asked Mar 23 '23 12:03

vidit


2 Answers

I think there are two pretty interesting things going on here.

The code tries to rely on a synchronization block to keep the order of the calls consistent. There are two problems with this:

1) The synchronization block isn't fair (see Synchronization vs Lock), so which ever thread gets to the locked synchronized block first may not be the first to be granted access to the object. According to that post, however, synchronization at the method level public synchronized void run() would be a fair lock (in Java 1.5, not Java 1.6), so the first one waiting on the lock would be the first granted access to the object.

2) Even if the synchronization block was fair, the first thread may not, in theory, (the [synchronized]) may not be the first to call some of the code in run(). The [world] could actually call it first.

like image 62
jmpyle771 Avatar answered Apr 06 '23 09:04

jmpyle771


No, the output is not guaranteed.

like image 26
jtahlborn Avatar answered Apr 06 '23 07:04

jtahlborn