2016-01-13 5 views
1

Возможно у меня есть следующее определение класса, когда одна нить хочет положить а для нескольких (потенциально) ожидающие потоки:Countdownlatch и далее синхронизация

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(); 
    } 
} 

кажется мне, что должно быть неустойчивыми, но я я не уверен ... Может ли кто-то рассказать, почему, если вообще, нужна ли дополнительная синхронизация вокруг getA, или нужно быть неустойчивым?

ответ

2

На самом деле a не нужно быть изменчивыми, поскольку countDown() loades и сохраняет в энергозависимой state переменную AbstractQueuedSynchronizer, которая используется внутри CountDownLatch. Неустойчивый магазин вызывает барьер памяти (great in-depth article about Memory Barriers and etc in JSR-133). И согласно JMM все предыдущие магазины (к другим переменным) будут видны другим потокам.
assylias прав, это правда, только если вы позвоните setA() один раз, потому что вы строите защелку как new CountDownLatch(1).

+0

Ах, поэтому в состоянии защелки есть неустойчивые чтения/записи. Это, в свою очередь, является полным барьером, поэтому изменения распространяются через кеши и т. Д. Правильно? – Bober02

+0

Да, именно это происходит. – dezhik

2

По the javadoc:

Пока счетчик не дойдет до нуля, действия в потоке перед вызовом countDown() произойти, прежде чем действия после успешного возвращения из соответствующего await() в другом потоке.

Таким образом, вам не нужна дополнительная синхронизация, если вы звоните только по номеру setA. Если вы вызовете его второй раз, потому что счетчик уже будет 0, вы не получите такую ​​же гарантию.

Если ожидаемое использование должно состоять только в вызове setA после того, как вы можете отправить исключение, если оно вызывается более одного раза, чтобы обеспечить выполнение этого контракта (хотя проверка количества и присвоение нового значения для атомарного атома может быть сложной без дополнительной синхронизации) ,

Если вы счастливы, что setA можно назвать более одного раза, вам потребуется дополнительная синхронизация.

+0

Большое спасибо! Как достигается эта последовательность памяти? Мне кажется, что защелка не имеет никакого отношения к классу A, чтобы иметь возможность синхронизировать состояние нескольких потоков ... – Bober02

+0

'Как достигается эта последовательность памяти?' Я описал это в своем ответе :) – dezhik

+0

@ Bober02 Все потоки чтения (вызов 'getA') будут читать' a' * после завершения '' await' (порядок программы). Пишущий поток (единственный поток, который вызывает 'setA'), вызывает' countDown' * после * записи в 'a' (порядок программы). Поскольку * происходит до того, как отношения являются транзитивными, гарантия, указанная в javadoc, означает, что запись в 'a' происходит до чтения' a'. Все это предполагает, что 'setA' вызывается только один раз. – assylias

Смежные вопросы