Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Relation between bytecode instructions and processor operations

Java specification guarantees primitive variable assignments are always atomic (expect for long and double types.

On the contrary, Fetch-and-Add operation corresponding to the famous i++ increment operation, would be non-atomic because leading to a read-modify-write operation.

Assuming this code:

public void assign(int b) {
    int a = b;
}

The generated bytecode is:

public void assign(int);
    Code:
       0: iload_1       
       1: istore_2      
       2: return 

Thus, we see the assignment is composed of two steps (loading and storing).

Assuming this code:

public void assign(int b) {
        int i = b++;
}

Bytecode:

public void assign(int);
    Code:
       0: iload_1       
       1: iinc          1, 1    //extra step here regarding the previous sample
       4: istore_2      
       5: return 

Knowing that X86 processor can (at least modern ones), operates increment operation atomically, as said:

In computer science, the fetch-and-add CPU instruction is a special instruction that atomically modifies the contents of a memory location. It is used to implement mutual exclusion and concurrent algorithms in multiprocessor systems, a generalization of semaphores.

Thus, first question: Despite of the fact that bytecode requires both steps (loading and storage), does Java rely on the fact that assignment operation is an operation always carried out atomically whatever the processor's architecture and so can ensure permanent atomicity (for primitive assignments) in its specification?

Second question: Is it wrong to confirm that with very modern X86 processor and without sharing compiled code across different architectures, there's no need at all to synchronize the i++ operation (or AtomicInteger)? Considering it already atomic.

like image 556
Mik378 Avatar asked Nov 15 '12 16:11

Mik378


1 Answers

Even if the i++ would translate into an X86 Fetch-And-Add instruction would change nothing because the memory mentionned in the Fetch-And-Add instruction refers to the local memory registres of the CPU and not to the general memory of the device/application. On a modern CPU, this property will extend to the local memory caches of the CPU and can even extend to the various caches used by the different cores for a multicores CPU but in the case of a multithreading application; there is absolutely no garanty that this distribution will extend to the copy of the memory used by the threads themselves.

In clear, in a multithread application, if a variable can be modified by different threads running at the same time then you must use some synchronisation mecanism provided by the system and you cannot rely on the fact that the instruction i++ occupies a single line of java code to be atomic.

like image 62
SylvainL Avatar answered Oct 10 '22 19:10

SylvainL