Потокобезопасность для статических переменных - PullRequest
14 голосов
/ 16 сентября 2011
class ABC implements Runnable {
    private static int a;
    private static int b;
    public void run() {
    }
}

У меня есть класс Java, как указано выше.У меня есть несколько потоков этого класса.В методе run() переменные a & b увеличиваются по несколько раз.На каждом шаге я помещаю эти переменные в Hashtable.

Следовательно, каждый поток будет увеличивать обе переменные и помещать их в Hashtable.Как я могу сделать эти операции потокобезопасными?

Ответы [ 4 ]

10 голосов
/ 16 сентября 2011

Я бы использовал AtomicInteger , который разработан как поточно-ориентированный, чрезвычайно прост в использовании и придает приложению абсолютный минимум накладных расходов синхронизации:

9 голосов
/ 16 сентября 2011

Зависит от того, что должно быть поточно-ориентированным.Для этих int примитивов вам нужно либо заменить их на AtomicInteger, либо работать с ними только в методе или блоке synchronized.Если вам нужно сделать свой многопоточный Hashtable поточно-безопасным, вам не нужно ничего делать, поскольку он уже синхронизирован.

6 голосов
/ 16 сентября 2011

Используйте метод synchronized, например,

public synchronized void increment()
{
  a++; b++;
  // push in to hash table.
}

. Вышесказанное хорошо, если вы обращаетесь к статике через один экземпляр, однако, если у вас есть несколько экземпляров, вам нужно синхронизировать некоторые статическиеобъект - что-то вроде (не проверено) ..

private static Object lock = new Object();

в методе

public void increment()
{
  synchronize(lock)
  {
    a++;b++;
    // do stuff
  }
}

ПРИМЕЧАНИЕ. Эти подходы предполагают, что вы хотите увеличить a и b в один атомарное действие, остальные ответы подчеркивают, как они могут быть индивидуально увеличены с использованием атомики.

2 голосов
/ 06 октября 2017

Я хотел бы добавить некоторые подробности об ответе на этот вопрос.

Во-первых, ОП спрашивает:

Как я могу сделать эти операции безопасными для потока?

Прежде чем ответить на этот вопрос, нам необходимо достичь согласованности относительно того, что поточно-ориентировано . Мне больше всего нравится определение из «Параллелизма Java на практике», и оно

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

Если вы согласны с определением, это означает, что мы достигли согласованности до дальнейшего обсуждения. Давайте вернемся к операциям, которые вы имели в виду, это a++ и b++, после приращения вы поместите их в HashTable.

Для операции a++ на самом деле это не единственная операция. Он подчиняется модели read modify write . Как видите, на самом деле он содержит три отдельных шага. Прочитайте значение, добавьте его и сохраните обратно. Если у вас есть два потока, прочитайте переменную a со значением 1 одновременно, после внесения изменений и сохранения обратных операций. Значение будет 2, но на самом деле оно должно быть 3. Чтобы избежать этой ситуации, как и другие, вы можете использовать AtomicInteger вместо int напрямую. AtomicInteger гарантирует, что некоторые операции, такие как инкремент, будут выполняться атомарно. Это означает, что операции read edit write не могут быть разделены и будут выполняться как один отдельный шаг.
После этого OP хочет сохранить значение в HashTable. HashTable - это потокобезопасный контейнер, никакой другой синхронизации не требуется.
Надеюсь, что это разъяснение может помочь кому-то по-другому. Спасибо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...