Multithreading: why this conclusion? Is it deterministic?

I am learning to write the best multithreaded programs, thread safe and deterministic. I stumbled upon 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 ~ 100 times)

 [Hello] [World] [Synchronized] 

So my first question is: is this guaranteed result? I also noticed that if I change the dream to 100 , it will still produce the same output, but if I hide from 10 output changes to

 [Hello] [Synchronized] [World] 

Second question: If it is guaranteed, why? Last but not least: Why this conclusion? I expected it to be

 [Hello] [Synchronized] [World] 
+4
source share
4 answers

I think there are two interesting things here.

The code tries to rely on a synchronization block to maintain a sequence of calls. There are two problems:

1) The synchronization block is unfair (see "Synchronization against blocking"), so when a thread ever gets into a locked synchronized block, at first it may not be the first to access the object. However, according to this post, synchronization at the level of the public synchronized void run () method will be a fair lock (in Java 1.5, not Java 1.6), so the first one waiting for the lock will be the first granted access to the object.

2) Even if the synchronization block was honest, the first thread may, theoretically, not be (synchronized), perhaps the first not to call some code in run (). [World] may actually call it the first.

+3
source

No, exit is not guaranteed.

+2
source

Warranty order is not guaranteed; the output is completely random, since it is determined by the OS, to which the processor should allocate a thread at a certain time. Algorithms that allocate flow time for the CPU are not deterministic.

To make print Hello, Synchronized, World code in this order, you must change Synch to:

 Caller ob1 = new Caller(target, "Hello"); ob1.t.join(); Caller ob2 = new Caller(target, "Synchronized"); ob2.t.join(); Caller ob3 = new Caller(target, "World"); ob3.t.join(); 

There is also no need for a synchronized block (as written), since only one thread will call the run method; also msg is read, not written to cause any problems, and the call method on target does not change the state of target in any way.

+1
source

The order of exits is not guaranteed. The synchronized block prevents the rotation of different streams when printing its outputs, but it does nothing to provide any order for three different outputs. The "deterministic" behavior that you see, unfortunately, is just random.

+1
source

Source: https://habr.com/ru/post/1487121/


All Articles