Являются ли эти два примера эквивалентными (volatile + синхронизированный инкремент или синхронизированный выбор + инкремент)? - PullRequest
0 голосов
/ 26 сентября 2018

Я исследовал различия между synchronized и volatile и написал пример без volatile, который, я считаю, эквивалентен примеру с volatile (из-за дополнительной синхронизации при извлечении)

Версия с Volatile

public class Volatile extends Super {
    private volatile int xCounter;
    private volatile int yCounter;

    @Override
    public int getXCounter() {
        return this.xCounter;
    }

    @Override
    public int getYCounter() {
        return this.yCounter;
    }

    @Override
    public void incrementXCounter() {
        synchronized (getLockXCounter()) {
            this.xCounter++;
        }
    }

    @Override
    public void incrementYCounter() {
        synchronized (getLockYCounter()) {
            this.yCounter++;
        }
    }
}

Версия без Volatile

public class NonVolatile extends Super {
    private int xCounter;
    private int yCounter;

    @Override
    public int getXCounter() {
        synchronized (getLockXCounter()) {
            return this.xCounter;
        }
    }

    @Override
    public int getYCounter() {
        synchronized (getLockYCounter()) {
            return this.yCounter;
        }
    }

    @Override
    public void incrementXCounter() {
        synchronized (getLockXCounter()) {
            this.xCounter++;
        }
    }

    @Override
    public void incrementYCounter() {
        synchronized (getLockYCounter()) {
            this.yCounter++;
        }
    }
}

Суперкласс

public abstract class Super {
    private final Object lockXCounter = new Object();
    private final Object lockYCounter = new Object();

    protected abstract int getXCounter();
    protected abstract int getYCounter();
    protected abstract void incrementXCounter();
    protected abstract void incrementYCounter();

    Object getLockXCounter() {
        return lockXCounter;
    }

    Object getLockYCounter() {
        return lockYCounter;
    }
}

В частности, Есть ли эквивалент между двумя примерами, представленными в следующих двух пунктах?

1) Производительность

2) Thread-Safety

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

Ответы [ 2 ]

0 голосов
/ 27 сентября 2018
  1. Проще говоря, первый - медленный для писателей, быстрый - для читателей, второй - для обоих (гипотетически).Следует отметить, что в некоторых архитектурах volatile по сути то же самое, что и синхронизация при реализации, поскольку базовой системе все еще необходимо сохранять согласованность памяти, поэтому может не иметь значения, используете ли вы какой-либо пример с точки зрения производительности.Все это говорит о том, что только я машу рукой в ​​воздухе и выдвигаю гипотезы, вы должны проверить и сравнить себя с вашими целевыми системами и убедиться в этом сами.Измерьте сейчас, оптимизируйте позже.

  2. Да, это потокобезопасно.Во-первых, более слабая согласованность, не всегда гарантируется, что вы увидите самое актуальное значение, потому что вы могли бы прочитать во время составного обновления, но если авторы не мешают друг другу, это не имеет значения, потому что это можеттолько максимум 1 следует за «фактическим» значением.Конечно, иногда важны строгие согласования, поэтому вам следует снова подумать о том, как это учитывается в ваших собственных целевых системах.

Эквивалентность немного сложнее ответить, но "это зависит".Опять же, иногда volatile - это то же самое, что и synchronized в базовой системе, но JMM не гарантирует этого.Что гарантировано, так это то, что записи будут видны читателям, записи будут атомарными по отношению к другим записям (но НЕ относительно чтений).

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


Или вы можете просто использовать AtomicInteger и получите лучшее из обоих миров: быстрое чтение и быстрая запись (за исключением некоторых сценариев, вы должны изучить LongAdder для высокой конкуренции).Выбор действительно остается за вами.

0 голосов
/ 26 сентября 2018

volatile считается более слабой формой синхронизации.Вы используете volatile для обеспечения видимости текущего значения при чтении, поэтому вы используете блокировку для всех операций с изменяющимися значениями и volatile для операций только для чтения.В тех случаях, когда блокировки разрешают доступ к значению только одному потоку, volatile-чтения допускают более одного, поэтому, когда вы используете volatile для защиты пути чтения кода, вы получаете более высокую степень совместного использования, чем если бы вы использовали блокировку для всего кодапути.Таким образом, производительность первого превосходит второе.

...