2016-11-10 3 views
0

У меня есть два потока, каждый из которых имеет свой счетчик: нить A имеет counterA, поток B имеет счетчик B. Каждый поток должен использовать оба счетчика: нить A должна использовать counterA и counterB, а также поток B должен использовать оба. Я использую AtomicInteger и делясь счетчиками между двумя потоками, которые я передаю им в качестве аргументов для потоков, и каждый поток хранит два счетчика в частных полях.безопасная публикация, аргумент, проходящий

// ... 
AtomicInteger counterA = new AtomicInteger(0); 
AtomicInteger counterB = new AtomicInteger(0); 

Thread tA = new Thread(new RunnableA(counterA, counterB)); 
Thread tB = new Thread(new RunnableB(counterA, counterB)); 

// ... in the constructor of RunnableA ... 
RunnableA(AtomicInteger counterA, AtomicInteger counterB) { 
    this.counterA = counterA; 
    this.counterB = counterB; 
} 

//... 
// The same for RunnableB 

Это safe publishing из двух счетчиков? Безопасная публикация необходима, поскольку ссылка на объект недостаточно безопасна для совместного использования объекта между потоками. Как я могу добиться безопасного опубликования в этом случае?

Заранее спасибо.

ответ

1

Термин «безопасная публикация» к этому не применим. Безопасная публикация - это публикация состояния, которое создается в конструкторе. В вашем примере объекты были созданы до того, как был вызван конструктор.

Если использовался какой-либо другой тип, это может быть или не быть безопасным в зависимости от того, были ли опубликованы переменные counterA и counterB. Однако, если счетчики реализованы как объекты AtomicInteger, вам не нужно беспокоиться о публикации. Они являются атомными/потокобезопасными, независимо от того, как они опубликованы. Единственный возможно концерн может быть публикацией состояния переменных экземпляра. Мы не можем сказать, происходит ли это, не глядя на остальную часть класса. Например:

  • являются переменными final или volatile?
  • если они являются энергонезависимыми и нефинальными, доступ к ним должным образом синхронизирован?
  • ли они ограничены потоками после того, как run() называется?

Обратите внимание, что runnables будет экземпляр в текущем потоке, а не в потоках, которые создаются, когда (и если) tA.start() и tB.start() называются. Когда вызывается start(), происходит между между вызовом start() текущего потока и вызовом нового потока run(). Это означает, что гарантируется безопасная публикация переменных для дочернего потока. Это вызывает только публикацию переменных для других потоков.

+0

«Я не могу сразу увидеть, как это может быть» - если к счетчикам обращаются за пределами вновь созданных потоков как переменные экземпляра Runnables. Значения, инициализированные в конструкторе, не гарантируются, чтобы быть видимыми перед доступом, если, например, объявить хотя бы одну из переменных экземпляра окончательной, см. Https://shipilev.net/blog/2014/safe-public-construction/ –

+0

Ну да ... но как можно получить эти переменные с помощью * ничего * до того, как конструктор вернется? Посмотрите на код для конструктора. (Я знаю, что означает безопасная публикация, а «final» - только один способ его достижения.) –

+0

«Когда вызывается start(), между вызовом start() текущего потока и запуском нового потока происходит событие(). Это означает, что гарантируется безопасная публикация переменных для дочернего потока ». Это то, что я считаю полезным. Например, не нужно объявлять «переменные аргументов» (this.counterA, this.counterB) как окончательные в Runnable, даже если Runnable сконструирован в основном потоке, а затем эти переменные аргументов доступны в созданный поток. –

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