Java изменчивый пользовательский объект - полная / глубокая видимость объекта - PullRequest
2 голосов
/ 02 мая 2020

У меня есть следующее:

public class MainClass {
    private final Map<Integer, List<MyCustomObject>> myMap = new HashMap<>();

    public synchronized addMyCustomObject(MyCustomObject customObj) {
        List<MyCustomObject> customObjList = myMap.get(customObj.getId());

        if (customObjList == null) {
            customObjList = new LinkedList<>();
        }
        customObjList.add(customObj);
    }

    public synchronized List<MyCustomObject> getList(int customObjId) {
        return myMap.get(customObjId);
    }
}

public class MyCustomObject {
    private volatile MyCustomObject sonCustomObject;
    private volatile int id;

    public MyCustomObject(MyCustomObject sonCustomObject, int id) {
        this.id = id;
        this.sonCustomObject = sonCustomObject;
    }

    public void changeId(int newId) {
        this.id = newId;
    }

    public int getId() {
        return this.id;
    }

    public void changeSon(MyCustomObject sonCustomObject) {
        this.sonCustomObject.setId(-1);
        this.sonCustomObject = sonCustomObject;
        this.sonCustomObject.setId(this.id);
    }
}

У меня следующие вопросы:

  1. Что произойдет, если с учетом MyCustomObject его идентификатор будет изменен? это изменение видимо другим потокам? (Без синхронизации) Я думаю, что да, ID это int и меняет свою ссылку.
  2. Что произойдет, если с учетом MyCustomObject его SON ID будет изменен? это изменение отражено в других темах? (Без синхронизации) Думаю, да, по предыдущей причине
  3. Что произойдет, если при задании ключевого слова MyCustomObject без изменчивого ключевого слова в его поле SON значение ID сына изменяется? Отражено ли это изменение в других темах? Я думаю, да, потому что id это int и меняет свою ссылку.

ПРАВИЛО THUMB: Давайте предположим следующее правило: Если сложный объект является общим, он должен быть синхронизируется, когда необходимо взаимное исключение, но синхронизация должна происходить и для тех полей, которые не меняют свою ссылку (т.е. сложные объекты вместо примитивов, таких как int или String). Это необходимо, потому что при использовании синхронизации все обновления доступны для безопасного использования java моделью памяти.

Спасибо

1 Ответ

0 голосов
/ 02 мая 2020

Ваш первоначальный вопрос: можно ли использовать volatile для получения последних обновлений карты?

Надеюсь, я правильно понял.

Представьте себе, если Thread B выполнит MyCustomObject() constructor: Это позволит сделать этот MyCustomObject доступным для других потоков (только когда они встречаются и читает volatile id). (рекомендуется, чтобы установка идентификатора была последним оператором в конструкторе). Однако может быть много таких объектов с таким же идентификатором, как в приведенном примере кода.

Представьте, если thread A выполнит addMyCustomObject(): Поток A получит последние обновления, включая правильно построенный экземпляр MyCustomObject.

Представьте себе, если thread C выполняет getList(): Это может или не может вернуть правильный результат. Карта является окончательной, поэтому она имеет правильно опубликованное состояние на момент ее создания. Однако это изменчивый держатель, и в этом заключается проблема. Вам потребуется синхронизация здесь.

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

Почему такое кодирование не рекомендуется? Приведенный выше код непонятен для чтения и использования в условиях параллельной среды. Это франк agile. Рекомендуется использовать конструкции синхронизации для уточнения взаимного исключения и видимости. Volatile имеет свои применения, такие как флаги.

Примечание. Volatile - для обеспечения видимости, а блокировка / синхронизация - для видимости и атомарности.

Пожалуйста, дайте мне знать в случае ошибки в моем объяснении.

Редактировать 1: Ответьте на ваши обновленные вопросы:

Q1: Что произойдет, если для MyCustomObject изменить его идентификатор? это изменение видимо другим потокам? (Нет синхронизации) Я думаю, да, ID является int и меняет свою ссылку.

A1: Нет, пока вызывающий поток не ссылается на id.

Q2: Что произойдет, если для MyCustomObject изменился идентификатор SON? это изменение отражено в других темах? (Без синхронизации) Я думаю, да, по предыдущей причине

A2: То же, что и выше.

Q3: Что произойдет, если для MyCustomObject без ключевого слова volatile на его Поле SON, значение ID сына изменяется? Отражено ли это изменение в других темах? Я думаю, что да, потому что id это int и меняет свою ссылку.

A3: Опять только когда volatile читается. Конечно, можно вызывать changeSon() снова и снова, и другой поток не увидит обновленный SON.

Наилучшим подходом будет создание многопоточного тестового жгута и выполнение тестовых примеров несколько раз по N. Я предполагаю, что у вас есть многоядерная система. Старайтесь не использовать виртуальную машину, которой назначено одно ядро.

...