2016-10-06 17 views
5

В качестве примера возьмем SimpleDateFormat, поскольку он не является потокобезопасным.volatile vs threadLocal в java

я мог позволить каждому потоку иметь свою собственную копию SimpleDateFormat используя ThreadLocal так:

private static final ThreadLocal<SimpleDateFormat> formatter = new ThreadLocal<SimpleDateFormat>(){ 
    @Override 
    protected SimpleDateFormat initialValue() 
    { 
     return new SimpleDateFormat("yyyyMMdd HHmm"); 
    } 
}; 

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

volatile SimpleDateFormat myformatter; 

и добиться той же безопасности потоков?

+1

Поскольку проблема безопасности потоков не возникает: проблема безопасности потока заключается в том, что 'SimpleDateFormat' имеет изменяемое состояние, которое не зависит от того, хранится ли эта ссылка в поле volatile. –

+1

Thread-local и 'volatile' не делают то же самое! С thread-local существует отдельная копия переменной для каждого потока. С 'volatile', все потоки разделяют одну переменную. Создание переменной 'volatile' не делает ее потокобезопасной, потому что' SimpleDateFormat' имеет внутреннее состояние, которое не должно обновляться несколькими потоками одновременно, как упоминал Энди. – Jesper

ответ

4

летучие гарантии ключевых слов, что поток будет иметь самый последнюю копию переменной

летучих переменная только, а не его поля.

Также, volatile полезен, только если вам нужно изменить значение переменной. В вашем случае использования, final выглядит как было бы более уместно:

private static final SimpleDateFormat format = ... 

Это также гарантирует, что вы будете иметь самое последнее значение переменной - потому что он может быть назначен только его значение один раз, и static final имеет гарантии видимость после полной загрузки класса.


Но это не причина, почему SimpleDateFormat не поточно все равно: он имеет изменяемое состояние, которое он использует для хранения промежуточных значений при форматировании даты.

Если один поток вызывает format, а другой также в методе format для одной и той же SimpleDateFormatter Например, эти промежуточные переменные получают топали непредсказуемо, что приводит к помехам между потоками, и, следовательно, непредсказуемо выход.

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

Короче говоря, volatile не предотвращает помехи от резьбы, и поэтому это не подходящая альтернатива ThreadLocal.

+1

'Из только изменчивой переменной, а не ее полей.' --- это на самом деле неточно, даже вводит в заблуждение, потому что вы будете наблюдать все записи в поля упомянутого объекта, которые писал поток записи, прежде чем писать в поле «volatile» , В этом суть безопасной публикации. –

+0

@MarkoTopolnik действительно? Я думаю о чем-то вроде 'System.out.println (volatileField.nonVolatileField);' - чтение 'volatileField' может дать вам видимость всех записей в' nonVolatileField' до этой точки; но не может быть обновлен «nonVolatileField» между чтением «volatileField» и «volatileField.nonVolatileField»? –

+0

Да, поэтому я говорю, что формулировка «вводит в заблуждение», а не «неверна». Похоже, вы не получаете гарантии _any_, кроме самой 'volatile'. С другой стороны, вы не получите гарантию соблюдения «последнего» состояния поля «volatile», потому что «последнее» не является даже четко определенной концепцией в JMM. Существенное различие заключается в последовательной согласованности и линеаризуемости. –

0

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

1

ThreadLocal - это средство, которое позволяет потокам иметь собственную локальную копию объекта. ThreadLocals лучше всего использовать с объектами, которые могут быть потокобезопасными в политике безопасности потоков от Ограничение потока (даже для многих объектов, которые не являются «потокобезопасными», поточное безопасное использование все еще возможно, если никакая ссылка на них не вытекает из ограничивающая нить). ThreadLocals не может помочь в потоковом использовании для изменяемых объектов, которые используются за пределами потока, который их создает.

Ключевое слово volatile используется для обеспечения слабой формы безопасности потоков с переменной, к которой могут обращаться многие различные потоки.Ключевым отличием является то, что ThreadLocals обычно не имеют доступа более чем к одному потоку.

Вообще говоря, безопасность потоков требует как видимости (последние обновления переменной должны быть видны другим потокам), так и взаимное исключение (переход состояния должен быть атомарным, чтобы состояние не могло считаться несогласованным). Volatile работает с моделью памяти Java, чтобы гарантировать, что переменная будет видимой, но она не дает никакой взаимной исключенности и, следовательно, не обеспечивает атомарность перехода состояний в объекты.

Потому что volatile и ThreadLocal настолько отличаются, что на самом деле нет общих обстоятельств, в которых вы могли бы заменить один на другой.