Этот вопрос обсуждался в двух сообщениях блога (http://dow.ngra.de/2008/10/27/when-systemcurrenttimemillis-is-too-slow/, http://dow.ngra.de/2008/10/28/what-do-we-really-know-about-non-blocking-concurrency-in-java/), но я еще не услышал окончательного ответа. Если у нас есть один поток, который делает это:
public class HeartBeatThread extends Thread {
public static int counter = 0;
public static volatile int cacheFlush = 0;
public HeartBeatThread() {
setDaemon(true);
}
static {
new HeartBeatThread().start();
}
public void run() {
while (true) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
counter++;
cacheFlush++;
}
}
}
И многие клиенты, использующие следующее:
if (counter == HeartBeatThread.counter) return;
counter = HeartBeatThread.cacheFlush;
это потокобезопасно или нет?




Ну не думаю.
Первый оператор if:
if (counter == HeartBeatThread.counter)
return;
Не обращается ни к одному изменчивому полю и не синхронизируется. Таким образом, вы можете читать устаревшие данные навсегда и никогда не дойти до точки доступа к изменчивому полю.
Цитата из одного из комментариев во второй записи блога: «все, что было видно потоку A, когда он записывал в изменчивое поле f, становится видимым потоку B, когда он читает f». Но в вашем случае B (клиент) никогда не читает f (= cacheFlush). Таким образом, изменения в HeartBeatThread.counter не должны становиться видимыми для клиента.
В рамках модели памяти Java? Нет, ты не в порядке.
Я видел несколько попыток перейти к такому подходу «мягкого флеша», но без явного ограничения вы определенно играете с огнем.
Семантика «происходит до» в
http://java.sun.com/docs/books/jls/third_edition/html/memory.html#17.7
начать называть чисто межпоточные действия «действиями» в конце 17.4.2. Это вызывает большую путаницу, поскольку до этого момента они различали меж- и внутрипотоковые действия. Следовательно, внутрипоточное действие по манипулированию счетчиком не синхронизируется явно через изменчивое действие посредством отношения «происходит до». У вас есть две цепочки рассуждений о синхронизации: одна управляет локальной согласованностью и подвергается всем красивым трюкам анализа псевдонимов и т. д. Для перемешивания операций. Вторая связана с глобальной согласованностью и определена только для межпотоковых операций.
Один для логики внутри потока, который говорит, что внутри потока операции чтения и записи последовательно переупорядочиваются, а другой для логики между потоками, который говорит, что такие вещи, как изменчивые чтения / записи и что начало / конец синхронизации должным образом изолированы.
Проблема заключается в том, что видимость энергонезависимой записи не определена, поскольку это операция внутри потока и, следовательно, не охватывается спецификацией. Процессор, на котором он работает, должен видеть его, когда вы выполняете эти операторы последовательно, но его упорядочение для межпотоковых целей потенциально не определено.
Теперь, реальность того, может ли это повлиять на вас, - совсем другой вопрос.
При запуске java на платформах x86 и x86-64? Технически вы находитесь на непонятной территории, но практически очень сильные гарантии, что x86 размещает на чтениях и записях, включая общий порядок чтения / записи при доступе к cacheflush и локальное упорядочение двух записей, и два чтения должны включать этот код. для правильного выполнения при условии, что это не мешает компилятору. Это предполагает, что компилятор не вмешивается и не пытается использовать свободу, разрешенную стандартом, для изменения порядка операций над вами из-за доказуемого отсутствия псевдонимов между двумя внутрипотоковыми операциями.
Если вы перейдете в память с более слабой семантикой выпуска, например ia64? Тогда ты снова сам по себе.
Однако компилятор может совершенно добросовестно сломать эту программу в java на любой платформе. То, что он работает прямо сейчас, является артефактом текущих реализаций стандарта, а не стандарта.
Кроме того, в CLR модель времени выполнения сильнее, и этот вид уловок является законным, потому что отдельные записи из каждого потока упорядочили видимость, поэтому будьте осторожны, пытаясь переводить любые примеры оттуда.