2

Please look at the below code -

class A {
    public int a;
    public int b;
}
A a = new A();

new Thread(new Runnable() {
  public void run() {
    System.out.println(a.a +" "+ a.b);
  }
}).start();

new Thread(new Runnable() {
  public void run() {
    a.a = 1;
    a.b = 3;
  }
}).start();

new Thread(new Runnable() {
  public void run() {
   a.a = 2;
   a.b = 4;
  }
}).start();

I know in a multi-threaded environment the output of above could not be predicted. Instance of A class is exposed to be updated by both the threads here and It's state is not thread-safe and rightly when I run the code I get output among {0 0}, {2 4} and {1 3}. Is it possible to get output as {1 4},{2 3},{0 4} or {2 0}? Why or Why Not ?

  • You can use a debugger to control step by step the advance of each of your threads, and reach the states you did not observe. But there are also more complex states that a debugger may not allow you to reach, see for example http://stackoverflow.com/questions/2576513/is-writing-a-reference-atomic-on-64bit-vms : some 64bit writes are sometimes non atomic... – GPI Jan 26 '17 at 11:18

5 Answers5

1

It may be impossible on a particular version of JVM for the particular piece of code, but it is possible in common case, as order of execution is not guaranteed by the Java Language Specification. The assignment statements may be reordered as there are no any happens-before constructions.

So writing a code such this you cannot rely on how it will be executed.

kan
  • 28,279
  • 7
  • 71
  • 101
  • I agree with kan. As the access to these variables is not synchronized it is possible that several threads access to one of the attribute and modify it while the other one is blocked due to a modification, what would cause a result like {1, 4}. This particular case would mean that, while 'a' was being blocked by a particular thread that tried to modify it, 'b' was modified by several other threads that are now waiting for 'a' to be released. From a general point of view (excluding particular JVM implementations), this case is possible – Facepalmed Jan 26 '17 at 11:13
  • Are you sure about order of statements? Chapter [14.2. Blocks](https://docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-14.2) of JLS 8 states: "A block is executed by executing each of the local variable declaration statements and other statements in order from first to last..." – user85421 Jan 26 '17 at 11:24
  • @CarlosHeuberger Yes, reordering of statements does not contradict with the paragraph, as observed effect will be identical unless you access same data from another thread - and [happens-before rules](https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.4.5) come to play. – kan Jan 26 '17 at 11:27
1

All above outputs are possible as there's no happens-before rule between thread modifications (synchronization method) and modifications could not be seen by other threads as shared instance fields are not volatile. Here's one of possible scenarios:

  • Thread B executes both lines, then
  • Thread C executes first line, then
  • Thread A outputs a.a and a.b values

In above scenario A might not see latest updates done by other threads, or it might see updates from C (only a.a) but not the ones done by B for field a.b and so on. Additionally, output cases for above case might slightly differ based on JVM implementation as well.

P.S You can check this playlist for more information about JMM and concurrency.

Zaur Guliyev
  • 4,254
  • 7
  • 28
  • 44
0

It is possible to get a "mixed" output like "1 4", but in a case like this with very short-lived threads, it is unlikely that their execution is interleaved.

If you want to make interleaved execution impossible, you must use a synchronized block (or similar mechanisms such as a ReentrantLock).

rrobby86
  • 1,356
  • 9
  • 14
  • As a bonus: if you want synchronized access on a **single** integer (or other primitive) field, you should take a look at `AtomicInteger` (or other `Atomic{PrimitiveType}`) – rrobby86 Jan 26 '17 at 11:09
  • synchronised is not the same as atomic. And AtomicInteger is not simplest solutino here, easier is to use "volatile". – kan Jan 26 '17 at 11:24
0

First of all, it is really not recommended to do this because, as you mentionned this is not thread-safe and the side-effects are unpredictable.

To answer to your question, I think it is theoretically possible you had the {1 4},{2 3},{0 4} or {2 0}. But your program is very simple so I'm not sure that it would happen.

Concurrency in Java is huge topic that we cannot discuss here because it would far too long. Also, there is a lot of documentation about it, I recommend you read it :

Example of documentation about Concurrency in Java :

Anatoly Shamov
  • 2,608
  • 1
  • 17
  • 27
Mickael
  • 4,458
  • 2
  • 28
  • 40
0

The output - {0 0}, {2 4} and {1 3} - that you are getting is as a result of random execution order of your three threads and has nothing to do with thread safety of class A.

The output - {1 4},{2 3},{0 4} or {2 0} that you are asking for is surely possible since you are not using volatile on primitives OR AtomicInteger, OR synchronized OR any other locks.Different approaches of synchronization have its pros and cons.

So why are you not seeing that output in any of your runs?

Primary reason seems your threads being very short lived and there is no thread suspension,context switching etc involved. Thread scheduling might be another reason that a thread gets a chance to run when another thread has completely finished as CPU cache etc gets flushed if thread has ended so intermediate values are not seen. System not being multi processor or not being multi core CPU might be another reason ( but that is hardly a reason these days).

You might try increasing thread run times by doing some I/O or by introducing busy waiting etc to see that behavior.

Hope it helps !!

Sabir Khan
  • 9,826
  • 7
  • 45
  • 98