Подтвердить что ты не робот

Безопасность резьбы для статических переменных

class ABC implements Runnable {
    private static int a;
    private static int b;
    public void run() {
    }
}

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

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

4b9b3361

Ответ 1

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

class ABC implements Runnable {
    private static AtomicInteger a;
    private static AtomicInteger b;
    public void run() {
        // effectively a++, but no need for explicit synchronization!
        a.incrementAndGet(); 
    }
}

// In some other thread:

int i = ABC.a.intValue(); // thread-safe without explicit synchronization

Ответ 2

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

Ответ 3

Используйте метод 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 за одно атомное действие, другие ответы показывают, как их можно индивидуально увеличить с помощью атомистики.

Ответ 4

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

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

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

Прежде чем ответить на этот вопрос, нам нужно достичь согласованности в отношении потокобезопасности. Определение, которое мне больше всего нравится, состоит в том, что из "Java Concurrency In Practice" и

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

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

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