6

In a recent answer I suggested that it is possible to achieve the functionality of volatile by synchronizing on the object containing the variable we need to be volatile (asker does not have access to the variable in code).

This got me thinking that I actually don't need to block on the containing object, I just need to achieve a memory barrier. As synchronized achieves both synchronisation and a memory barrier, if all I need is the memory barrier (as in this case) would it actually be better to use synchronized(new Object()) to achieve my memory barrier and ensure the lock is never contended?

Community
  • 1
  • 1
OldCurmudgeon
  • 64,482
  • 16
  • 119
  • 213
  • See also: http://stackoverflow.com/questions/37142411/why-is-synchronized-new-object-a-no-op – yankee Aug 11 '16 at 14:49

3 Answers3

3

As explained here: http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#synchronization synchronized(new Object()) is considered a noop and may be removed entirely by the compiler. You won't get a memory barrier out of it.

Cola Colin
  • 233
  • 1
  • 2
  • 10
2

would it actually be better to use synchronized(new Object()) to achieve my memory barrier and ensure the lock is never contended?

Nop. The JVM can easily prove that this lock can't be accessed by two threads (since it is a thread-local variable) and will almost certainly turn it into a no-op, i.e. completely remove the synchronized statement.

assylias
  • 321,522
  • 82
  • 660
  • 783
  • So how can I achieve a memory barrier like `volatile` does without setting the actual variable `volatile` while minimising/eliminating lock contention? – OldCurmudgeon May 23 '13 at 10:34
  • @OldCurmudgeon I have seen something in the sun.misc package but not sure if it was in JDK 7 or 8 (something like: unsafe.load / unsafe.store) - can't dig it out now. – assylias May 23 '13 at 10:37
2

In addition to @assylias's very good point, also consider that synchronized does not achieve a memory barrier by specification. It is only the case that this is how it is implemented on today's typical CPU-memory architectures. The specification only guarantees what happens when two threads acquire the same lock.

Anyway, if you don't care about the specification, but only about the real-world implementations, then why not introduce your own volatile variable and simply write to it whenever you want a memory barrier? It is irrelevant which volatile you write to, as long as we're talking about a constrained set of architectures which is implied by your synchronized(new Object()) idea.

Marko Topolnik
  • 195,646
  • 29
  • 319
  • 436
  • I think that is the critical point I am missing - the barrier only applies to all the sharers of the specific lock object. Although most discussion on this subject mentions flushing caches, it would be quite possible for an implementation to merely push cached values from one cpu to another. – OldCurmudgeon May 23 '13 at 10:42
  • In the question, asker wanted to call a `set...` method of an object they do not have control over from multiple threads. The variable cannot be made `volatile`. – OldCurmudgeon May 23 '13 at 10:44
  • Yes, I expect this to happen as the number of execution units (cores or whatever) grows. In massively parallel systems there is no cache coherency, and I think the mainstream is firmly set on this road now. – Marko Topolnik May 23 '13 at 10:45
  • Unfortunately there is no Java primitive that has the exact semantics of "memory barrier". – Marko Topolnik May 23 '13 at 10:48
  • After your edit - are you suggesting that accessing **any** volatile variable will invalidate **all** cached values? I would have thought only **that** variable would be flushed in that case. – OldCurmudgeon May 23 '13 at 10:53
  • Definitely not only that one, and this is by specification: everything *reachable* from that var (if it's reference-typed, of course) must be flushed as well. This was a key motivator of the great rewrite of the Java Memory Model for Java 1.5. – Marko Topolnik May 23 '13 at 10:55
  • 1
    Pardon me, I think it's actually *all actions of the thread that did the write are visible to the thread that is doing the read*---which comes very close to an actual memory barrier! – Marko Topolnik May 23 '13 at 10:56