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

Динамическая синхронизированная комбинация для производительности

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

public class Counter
{
    private volatile int count;

    public Counter()
    {
        count = 0;
    }

    public int getCount()
    {
        return count;
    }

    public synchronized void increment()
    {
        ++count;
    }   
}

Пожалуйста, дайте мне знать, в каком сценарии это может сломаться?

4b9b3361

Ответ 1

Да, вы определенно можете. На самом деле, если вы посмотрите на исходный код AtomicInteger, это, в сущности, то, что они делают. AtomicInteger.get просто возвращает value, который является ссылкой volatile int (). Единственное реальное отличие от того, что вы сделали и что они делают, это то, что они используют CAS для приращения вместо синхронизации. На современном оборудовании CAS может устранить любое взаимное исключение; на более старом оборудовании, JVM поместит какой-то мьютекс вокруг приращения.

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

Не только это, но volatile поля гарантированно не разрываются: см. JLS 17.7, в котором указано, что volatile long и double не подлежат разрыву слова. Таким образом, ваш код будет работать с long так же, как и int.

Как указывает Диего Френер, вы можете не увидеть результат приращения, если вы получите значение "прямо как" приращение, вы увидите либо до, либо после. Конечно, если get были синхронизированы, у вас было бы точно такое же поведение из прочитанного потока - вы либо увидите значение до-инкремента или пост-приращения. Так что это действительно так же в любом случае. Другими словами, не имеет смысла говорить, что вы не увидите значения, как это происходит, если только вы не имеете в виду разрывание слова, которое (а) вы не получите, и (б) вы никогда не захотите.

Ответ 2

1. Я лично использовал этот механизм volatile в сочетании с synchronized.

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

3. Это связано с тем, что ключевое слово volatile не является примитивом синхронизации. Он просто предотвращает кеширование значения в потоке, но он не мешает двум нити изменять одно и то же значение и записывать его одновременно.

4. volatile предоставляют одновременный доступ к потокам без блокировки, но с помощью synchronized разрешает только один поток, чтобы получить доступ к этому и все синхронизированные методы в классе.

5. И , используя как volatile and synchronized, сделает это....

volatile - будет отображать измененные значения в потоке и предотвращать кеширование,

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

Ответ 3

При вызове getCount() вы не всегда будете получать наиболее актуальный счет. AtomicInteger может быть подходящим для вас.

Ответ 4

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