2008-11-07 2 views
3

Этот вопрос обсуждался в двух блогах (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; 

является его поточно или нет?

ответ

5

В модели памяти java? Нет, ты не в порядке.

Я видел несколько попыток подойти к очень «мягкому флешу», подобному этому, но без явного забора вы определенно играете с огнем.

«происходит до» семантики

http://java.sun.com/docs/books/jls/third_edition/html/memory.html#17.7

начала в виде чисто межпоточное действие как «действия» в конце 17.4.2, Это приводит к большой путанице, так как до этого они различают меж- и внутрипоточные действия. Следовательно, внутрипоточное действие манипулирующего счетчика явно не синхронизируется во время изменчивого действия с помощью отношения «происходить-до». У вас есть две темы рассуждений о синхронизации, одна управляет локальной согласованностью и подчинена всем приятным трюкам анализа псевдонимов и т. Д., Чтобы перетасовывать операции. Другое относится к глобальной согласованности и определяется только для операций с несколькими потоками.

Один для логики внутрипотока, который говорит в потоке, чтение и запись последовательно переупорядочиваются, а одна для логики межпоточных, которая говорит такие вещи, как изменчивые чтения/записи, и что запуск/завершение синхронизации должным образом огорожены.

Проблема заключается в том, что видимость энергонезависимой записи не определена, поскольку она является внутрипоточной операцией и поэтому не покрывается спецификацией. Процессор, на котором он работает, должен иметь возможность видеть его, поскольку он выполнял эти операторы серийно, но его секвенирование для межпоточных целей потенциально не определено.

Теперь реальность того, может ли это повлиять на вас, - это совсем другое дело.

Во время работы java на платформах x86 и x86-64?Технически вы находитесь в мутной территории, но практически очень сильные гарантии x86 места на чтение и запись, включая общий порядок чтения/записи через доступ к кешфлефу, и локальный порядок на двух записях, а два чтения должны включать этот код для правильного выполнения, если он делает это без компромиссов. Это предполагает, что компилятор не вступает и пытается использовать свободу, разрешенную стандартом, для изменения порядка операций на вас из-за доказуемого отсутствия сглаживания между двумя операциями внутри потока.

Если вы переместитесь в память с более слабой семантикой выпуска, например, ia64? Тогда вы вернулись сами.

Компилятор мог в совершенно добросовестности разбить эту программу в java на любой платформе. То, что он функционирует прямо сейчас, является артефактом текущих реализаций стандарта, а не стандартом.

Как и в случае с CLR, модель времени выполнения более сильная, и этот вид трюка является законным, потому что человек, который пишет из каждого потока, имеет упорядоченную видимость, поэтому будьте осторожны, пытаясь перевести любые примеры оттуда.

1

Ну, я не думаю, что это так.

Первый Условный оператор:

if (counter == HeartBeatThread.counter) 
    return; 

Не доступ к любому летучего поля и не синхронизирован. Таким образом, вы можете читать устаревшие данные навсегда и никогда не получить доступ к нестабильному полю.

Цитата из одного из комментариев во второй записи блога: «все, что было видимо для потока A, когда оно записывает в нестабильное поле, становится видимым для потока B, когда оно читает f». Но в вашем случае B (клиент) никогда не читает f (= cacheFlush). Поэтому изменения в HeartBeatThread.counter не должны становиться видимыми для клиента.

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