Необходимо реализовать Выполнимый, но если Вы работаете на Java 5 или выше, Вы не должны запускать его с new Thread
, но использовать ExecutorService вместо этого. Для получения дополнительной информации см.: , Как реализовать простую поточную обработку в Java.
Вы используете volatile
/ Thread.MemoryBarrier ()
, если хотите получить доступ к переменной в потоках без блокировки.
Атомарные переменные как, например, int
, всегда читаются и записываются целиком одновременно. Это означает, что вы никогда не получите половину значения до того, как другой поток изменит его, а другую половину - после его изменения. Из-за этого вы можете безопасно читать и записывать значение в разных потоках без синхронизации.
Однако компилятор может оптимизировать некоторые операции чтения и записи, что можно предотвратить с помощью ключевого слова volatile
. Если, например, у вас есть такой цикл:
sum = 0;
foreach (int value in list) {
sum += value;
}
Компилятор может фактически выполнять вычисления в регистре процессора и записывать значение в переменную sum
только после цикла.
Что не так с
private static readonly object syncObj = new object();
private static int counter;
public static int NextValue()
{
lock (syncObj)
{
return counter++;
}
}
?
Это делает за вас все необходимые блокировки, барьеры памяти и т.д. Он хорошо понятен и более читабелен, чем любой пользовательский код синхронизации, основанный на volatile
и Thread.MemoryBarrier ()
.
EDIT
Я не могу придумать сценарий, в котором Я бы использовал volatile
или Thread.MemoryBarrier ()
. Например,
private static volatile int counter;
public static int NextValue()
{
return counter++;
}
не эквивалентно приведенному выше коду и не потокобезопасный ( volatile
не делает ++
В таком случае:
private static volatile bool done;
void Thread1()
{
while (!done)
{
// do work
}
}
void Thread2()
{
// do work
done = true;
}
(который должен работать) я бы использовал ManualResetEvent , чтобы сигнализировать о завершении Thread2.
В основном, если вы используете какой-либо другой вид синхронизации, чтобы сделать ваш код потокобезопасным, то в этом нет необходимости.
Большинство механизмов блокировки (включая блокировку) автоматически подразумевают память барьер, чтобы несколько процессоров могли получать правильную информацию.
Volatile и MemoryBarrier в основном используются в сценариях без блокировки, когда вы пытаетесь избежать потери производительности от блокировки.
Изменить: Вы должны прочитать ] эта статья Джо Даффи о модели памяти CLR 2.0, она многое проясняет (если вам действительно интересно, вы должны прочитать ВСЮ статью Джо Даффи, который в целом является наиболее опытным специалистом в области параллелизма. NET)