0

I understand that if this was about a HashMap or some other complex object I would still need to add synchronized. But is this also the case for primitives? My intuitive feeling is that I don't need it, but I'm not certain.

Tigris
  • 133
  • 8
  • Well, do you mind that certain threads never get updated values of the integer at all? If you can guarantee that a single thread writes – and no other one does, then you don't need to synchronize. You may also take a look at the [`volatile` keyword](https://stackoverflow.com/questions/106591/what-is-the-volatile-keyword-useful-for), which is about *memory visibility*. – MC Emperor Oct 16 '20 at 10:06
  • I don't mind that they get the previous value, no. – Tigris Oct 16 '20 at 10:08
  • What about a never assigned value, seeing some primitive writes or read are not atomic ? https://stackoverflow.com/a/1006712/2131074 – GPI Oct 16 '20 at 16:31

1 Answers1

2

If you do not add a 'happens before' relation between a read and a write, you could end up with a data race. if there is a data race, all bets are off. The compiler could optimize the code in such a way you will never see the new value.

If you want to have very cheap access, you could do an acquire load and a store release.

E.g. https://docs.oracle.com/en/java/javase/13/docs/api/java.base/java/util/concurrent/atomic/AtomicLong.html

AtomicLong.getAcuire

AtomicLong.storeRelease

On the X86 platform every load is an acquire load and every store is a release store. So you will get this totally for free on the hardware level. However it will prevent certain compiler optimizations.

If you care a little bit less for extreme performance, then a volatile would be sufficient. This will give you a sequential consistent load and store. The main issue on the hardware level is that it blocks the CPU from executing any loads till store buffer is drained to the Level 1 cache. A volatile load is equally expensive on a hardware level as an acquire load; the price for sequential consistency is at the write.

pveentjer
  • 10,545
  • 3
  • 23
  • 40
  • 2
    Using `getAcquire` will prevent the classical compiler optimization of turning `while (running) {}` into `boolean __localRunning = running; while (__localRunning) {}`. Well, even opaque access does that. – Johannes Kuhn Oct 17 '20 at 03:35