Атомные переменные в синхронизированных блоках - PullRequest
0 голосов
/ 22 мая 2018

Я имею в виду язык Java, но думаю, что он может касаться и других языков.

Вопрос в следующем: имеет ли смысл помещать атомарную переменную в синхронизированный блок? Или достаточно того, что синхронизированный блок не будет выполняться двумя потоками одновременногарантировать, что операции, выполняемые в синхронизированном блоке, являются атомарными?(Пример 1 против примера 2)

Пример 1:

public class SharedVariables {
  public static AtomicInteger i;
}

public class MyThread extends Thread {
  public void run() {
    synchronized(SharedVariables.i) {
      i.getAndIncrement();
    }
  }
}

Пример 2:

public class MyIntegerWrapper {
  public int i;
  public void increment() {
    this.i++;
  }
}

public class SharedVariables {
  public static MyIntegerWrapper i;
}

public class MyThread extends Thread {
  public void run() {
    synchronized(SharedVariables.i) {
      i.increment();
    }
  }
}

Ответы [ 5 ]

0 голосов
/ 22 мая 2018

В первом примере вы используете две синхронизации.

В AtomicInteger реализован алгоритм " Неблокирующая синхронизация * "

Точно Выглядите свободно Алгоритм, который позволяетотдельные потоки, чтобы голодать, но гарантирует пропускную способность всей системы.

Этот алгоритм работает с помощью машинных инструкций.Например, в архитектурах x86 (начиная с 80486) и Itanium это реализовано как инструкция сравнения и обмена (CMPXCHG).

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

Поэтому, в вашем случае не используйте синхронизированный блок, используйте AtomicInteger.

0 голосов
/ 22 мая 2018

В ваших примерах вполне нормально использовать либо AtomicInteger без synchronized, либо MyIntegerWrapper внутри synchronized.

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

Кроме того, что выбрать, зависит от того, как часто изменяется переменнаяпо разным темам.AtomoicInteger использует сравнить и установить (или просто cas) операцию внутри вместо синхронизации.Считается, что CAS работает быстрее, поскольку затраты по сравнению с входом в блок synchronized меньше, однако в случае высокой конкуренции (когда множество потоков пытается изменить эту переменную одновременно), блок synchronized может быть более эффективным.Также synchronized дает jvm пространство для некоторых оптимизаций, таких как грубая блокировка.Так что имейте это в виду при выборе AtomicInteger вместо synchronized.

0 голосов
/ 22 мая 2018

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

0 голосов
/ 22 мая 2018

Не само по себе нет.Но если вы выполняете операцию, которая включает в себя потокобезопасный класс, такой как AtomicInteger и другие переменные (даже если они другие AtomicIntegers), вам может понадобиться.

AtomicInteger гарантирует, чтооперации над ним поточнобезопасны и атомарны без необходимости что-либо делать.Но допустим, что вы увеличиваете одно и уменьшаете другое, и их сумма всегда должна быть одинаковой.У вас есть 2 атомарных операции, но чтобы объединить их в одну атомарную операцию, вам потребуется дополнительная синхронизация.Только тогда вы можете быть уверены, что другие потоки будут считывать постоянную сумму этих переменных.

Я по-прежнему был бы осторожен, комбинируя ручную синхронизацию с классами java.util.concurrent, так как, скорее всего, есть более чистое решение, обеспечиваемоеодновременные занятия.

0 голосов
/ 22 мая 2018

synchronized не требуется в вашем первом коде, достаточны гарантии атомарных переменных.

У вашего второго кода есть одна проблема: переменная int общедоступна, поэтому вы не можете гарантировать, чтоон всегда будет вызываться из блока synchronized.

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