Is id = 1 - is atomic id?

From page 291 of the Java SE 6 programming exam exam, question 25:

public class Stone implements Runnable { static int id = 1; public void run() { id = 1 - id; if (id == 0) pick(); else release(); } private static synchronized void pick() { System.out.print("P "); System.out.print("Q "); } private synchronized void release() { System.out.print("R "); System.out.print("S "); } public static void main(String[] args) { Stone st = new Stone(); new Thread(st).start(); new Thread(st).start(); } } 

One answer:

The output may be PQPQ

I correctly answered this answer. My reasoning:

  • We start two streams.
  • run() is entered first.
  • According to JLS 15.26.1, it first evaluates to 1 - id . Result 0 . It is stored in the thread stack. We are going to save this 0 in static id , but ...
  • Boom, the scheduler is picking a second thread to run.
  • So, the second thread goes into run() . The static id is still 1 , so it executes the pick() method. PQ .
  • The scheduler selects the first thread to start. It takes 0 from its stack and saves to a static id . So, the first thread also does pick() and prints PQ .

However, the book says that this answer is incorrect:

This is not true because the line id = 1 - id changes the id value between 0 and 1 . It is not possible for the same method to be executed twice.

I do not agree. I think there is a chance for the scenario that I presented above. Such an exchange is not atomic. I'm wrong?

+72
java multithreading atomic swap scjp
Nov 23 '14 at 12:56
source share
2 answers

I'm wrong?

No, you are absolutely right - as your timeline.

In addition to this, it is not atomic, it does not guarantee that the entry in id will be picked up by another thread in any case, given that there is no synchronization and the field is not mutable.

This is somewhat confusing as reference material like this is incorrect :(

+77
Nov 23 '14 at 13:01
source share

In my opinion, the answer on the practical exams is correct. In this code, you are executing two threads that have access to the same static variable identifier. Static variables are stored on the heap in java, not on the stack. The execution order of runnables is unpredictable.

However, to change the id value of each thread:

  • makes a local copy of the value stored in the id memory address in the CPU registry;
  • performs operation 1 - id . Strictly speaking, two operations are performed here (-id and +1) ;
  • returns the result back to the id memory on the heap.

This means that although the id value can be changed simultaneously by one of the two threads, only the start and end values ​​are mutable. Intermediate values ​​will not be changed by each other.

Moreover, code analysis can show that at any given time id can only be 0 or 1.

Evidence:

  • Initial value id = 1; One thread will change it to 0 ( id = 1 - id ). And another thread will return it to 1.

  • Initial value id = 0; One thread will change it to 1 ( id = 1 - id ). And another thread will return it to 0.

Therefore, the state of the id value is discrete either 0 or 1.

The end of the proof.

There can be two possibilities for this code:

  • Opportunity 1. In a stream, one first accesses the variable identifier. Then the id value ( id = 1 - id will change to 0. After this, only the pick () method will be executed by printing PQ . The second stream will evaluate id at this time id = 0 , then the release() method will print R S. As a result, PQRS will be printed.

  • Opportunity 2. In a stream, two first access the variable identifier. Then the id value ( id = 1 - id will change to 0. After this, only the pick () method will be executed by printing PQ . In the first case, the identifier will be evaluated at that time id = 0 ; then the release() method will print R S. As a result, PQRS will be printed.

There are no other possibilities. However, it should be noted that PQRS variants, such as PRQS or RPQS , etc., can be printed due to the fact that pick() is a static method and therefore is split between two streams. This leads to the simultaneous execution of this method, which can lead to printing letters in a different order depending on your platform.

However, in any case, the two pick() or release () methods will never be executed, since they are mutually exclusive . Therefore, PQPQ will not be output.

-one
Nov 27 '14 at 21:43
source share



All Articles