Where is the load barrier for erratic applications?

I wrote this simple Java program:

package com.salil.threads; public class IncrementClass { static volatile int j = 0; static int i = 0; public static void main(String args[]) { for(int a=0;a<1000000;a++); i++; j++; } } 

This generates the following disassembled code for i ++ and j ++ (the remaining disassembled code is removed):

  0x0000000002961a6c: 49ba98e8d0d507000000 mov r10,7d5d0e898h ; {oop(a 'java/lang/Class' = 'com/salil/threads/IncrementClass')} 0x0000000002961a76: 41ff4274 inc dword ptr [r10+74h] ;*if_icmpge ; - com.salil.threads.IncrementClass::main@5 (line 10) 0x0000000002961a7a: 458b5a70 mov r11d,dword ptr [r10+70h] 0x0000000002961a7e: 41ffc3 inc r11d 0x0000000002961a81: 45895a70 mov dword ptr [r10+70h],r11d 0x0000000002961a85: f083042400 lock add dword ptr [rsp],0h ;*putstatic j ; - com.salil.threads.IncrementClass::main@27 (line 14) 

Here is what I understand about the following assembler:

  • mov r10,7d5d0e898h: moves the pointer to IncrementClass.class to register r10
  • inc dword ptr [r10 + 74h]: increments the value of 4 bytes at the address by [r10 + 74h], (ie)
  • mov r11d, dword ptr [r10 + 70h]: moves the value of value 4 to the address [r10 + 70h] for registering r11d (for example, the value of moving j in r11d)
  • inc r11d: Increment r11d
  • mov dword ptr [r10 + 70h], r11d: write the value r11d to [r10 + 70h] so that it is visible to other threads -lock add dword ptr [rsp], 0h: block the memory address represented by the pointer to the rsp stack and add to him 0.

JMM states that there should be a load memory barrier before every volatile read, and there should be a storage barrier after every volatile write. My question is:

  • Why is there no load barrier before reading j in r11d?
  • How locking and adding to rsp ensures that the j value in r11d is passed back to main memory. All I read from the intel specs is that locking provides the processor with exclusive locking at the specified memory address for the duration of the action.
+8
java assembly multithreading intel
source share
3 answers

The Intel x86 processor has a strong memory model .

Therefore, all barriers StoreStore, LoadLoad, LoadStore do not work on x86. With the exception of StoreLoad, which can be implemented via mfence or cpuid or blocked by insn . Which you can already confirm with your build code. Other barriers simply mean limiting the optimization and conversion of compilers so that they do not violate the specification of the java memory model .

When you started the Intel processor, I guess its x86.

Read please

A lock is not an instruction, but more of a command prefix (behaves like a storage barrier).

  • What does the β€œlock” command mean in x86 assembly?
  • Why do we need a lock prefix before CMPXCHG
+5
source share

volatile keyword in Java ensures that local copies and stream caching are skipped and the value is loaded directly from main memory or written to main memory. However, it does not contain a locking mechanism. Thus, reading from volatile or writing to volatile is atomic, but represents a series of read and write operations, such as your previous ones

j++

It is NOT atomic, because some other thread can change the value of j between reading and writing to a variable in main memory. To achieve atomic increment, you need to use CAS operations that are wrapped in Atomic classes in java, such as AtomicInteger , etc. Alternatively, if you prefer low-level programming, you can use atomic methods in the Unsafe Eg class, Unsafe.compareAndSwapInt , etc.

+3
source share

The barrier can be optimized by your JIT compiler, since your program is single-threaded (there is only a thread - the main thread), just as blocking in a single-threaded environment can be optimized. This optimization is independent of the processor architecture.

0
source share

All Articles