Countdownlatch and further synchronisation
Asked Answered
G

2

5

Supposedly I have the following class definition, when one thread wants to set a for multiple (potentially) waiting threads:

public class A {
    private int a;
    private CountDownLatch gate;

    public A(int a) {
        a = 1;
        gate = new CountDownLatch(1);
    }

    public int getA() {
        latch.await();
        return a;
    }

    public void setA(int a) {
        this.a = a;
        gate.countDown();
    }
}

It seems to me that a needs to be volatile, but I am not sure… Could someone please share why, if at all, there needs to be an extra synchronization around getA, or a needs to be volatile?

Garratt answered 13/1, 2016 at 10:44 Comment(0)
G
4

Actually a doesn't need to be volatile because countDown() loades and stores into volatile state variable of AbstractQueuedSynchronizer which is used inside CountDownLatch. Volatile store triggers a memory-barrier (great in-depth article about Memory Barriers and etc in JSR-133). And according to the JMM all previous stores (to other variables) would be visible to other threads.
assylias is right, it would be true only if you call setA() once, because you construct latch as new CountDownLatch(1).

Gland answered 13/1, 2016 at 11:2 Comment(2)
Ah, so there are volatile reads/writes inside the latch's state. That in turn is a full barrier so the changes are propagated across caches etc. Correct?Garratt
Yes, exactly this happens.Gland
C
5

According to the javadoc:

Until the count reaches zero, actions in a thread prior to calling countDown() happen-before actions following a successful return from a corresponding await() in another thread.

So you don't need extra synchronisation if you only call setA once. If you call it a second time, because the count will already be 0, you won't get the same guarantee.

If the expected use is to only call setA once you could throw an exception if it is called more than once to enforce that contract (although checking the count AND assigning a new value to a atomically may be tricky without additional synchronisation).

If you are happy that setA can be called more than once then you need additional synchronisation.

Cyrilla answered 13/1, 2016 at 10:53 Comment(5)
Thanks a lot! How is this memory consistency achieved? Seems to me that the latch does not have any relationship to class A to be able to synchronize the state of a across multiple threads...Garratt
How is this memory consistency achieved? I described this in my answer :)Gland
@Garratt All the reading threads (calling getA) will read a after await completes (program order). The writing thread (the one and only thread that calls setA) is calling countDown after writing to a (program order). Because happens-before relationships are transitive, the guarantee given in the javadoc means that the write to a happens-before the reads of a. All this assumes setA is only called once.Cyrilla
Agreed, but this is still high level. Volatile writes/barriers were more down my alleyGarratt
@Garratt I'm not sure what you expect - working with happens-before relationships is enough in this case. You may refer to processor barrier instructions but these are not part of the Java Memory Model (even if JVMs generally use them to implement the JMM).Cyrilla
G
4

Actually a doesn't need to be volatile because countDown() loades and stores into volatile state variable of AbstractQueuedSynchronizer which is used inside CountDownLatch. Volatile store triggers a memory-barrier (great in-depth article about Memory Barriers and etc in JSR-133). And according to the JMM all previous stores (to other variables) would be visible to other threads.
assylias is right, it would be true only if you call setA() once, because you construct latch as new CountDownLatch(1).

Gland answered 13/1, 2016 at 11:2 Comment(2)
Ah, so there are volatile reads/writes inside the latch's state. That in turn is a full barrier so the changes are propagated across caches etc. Correct?Garratt
Yes, exactly this happens.Gland

© 2022 - 2024 — McMap. All rights reserved.