Как сделать поток Java класса безопасным? - PullRequest
3 голосов
/ 13 марта 2019

У меня есть класс Java, как показано ниже

 class User {

    String name;
    String phone;

    public String getName() {
        return name;
    }

    public String getPhone() {
        return phone;
    }

}

Способ использования этого класса: для каждого потока создается 1 объект этого класса User. Теперь, поскольку для каждого потока существует одна копия объекта, могу ли я назвать этот класс безопасным для потока?

Нужно ли синхронизировать эти методы?

Ответы [ 3 ]

0 голосов
/ 13 марта 2019

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

Для этого класса, хотя методов записи нет, вам все равно нужно синхронизировать чтения.Это связано с тем, что компилятор может кэшировать переменные состояния (в данном случае name и phone) для каждого потока (помните, что каждый поток имеет свой собственный набор регистров).Таким образом, если один поток обновляет значение какой-либо из переменных состояния, другой поток может не увидеть его и может прочитать устаревшее значение.

Очень простой способ избежать этого - создать переменные состоянияvolatile.Это слабый примитив синхронизации, и он не обеспечивает атомарного поведения, как synchronised.

Вот правильный способ сделать поток этого класса безопасным:

 class User {

    GuardedBy("this")String name;
    GuardedBy("this")String phone;

    public synchronised String getName() {
        return name;
    }

    public synchronised String getPhone() {
        return phone;
    }

}

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

Слабая синхронизация:

 class User {

    volatile String name;
    volatile String phone;

    public String getName() {
        return name;
    }

    public String getPhone() {
        return phone;
    }

}

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

Стационарное чтение может быть еще более опасным с 64b doubleи long, поскольку запись и чтение в эти типы данных в Java не являются атомарными, и могут быть выполнены в 2 32b операциях.Это может привести к очень плохим последствиям.

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

0 голосов
/ 13 марта 2019

Thread Safe Class означает, что все изменения (получение / установка значений) в вашем POJO классе сделаны Thread Safely.

Это может быть достигнуто механизмом синхронизации.

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

Это ключевое слово просто блокирует объект, и вам гарантировано, что только один поток будет доступен для доступа к этому методу в любой момент времени.

Но лучшая практика (оптимизированорешение) состоит в том, чтобы уменьшить критический участок кода и не всегда использовать synchronized для простого / «быстрого» решения.

0 голосов
/ 13 марта 2019

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

Другое дело - если вы объявите свои поля как private и создайте экземпляр этого класса как final, тогда он будет неизменным (final User user = new User(...)).Здесь нет сеттеров, поэтому объект нельзя изменить, равно как и изменить его ссылку.Если вы хотите сохранить неизменность, вам придется заставить установщики возвращать новый экземпляр этого объекта с измененными полями.

@ markspace заметил, что лучшим подходом было бы объявить поля как окончательные, потому что если вы используетепредыдущий и сделать User членом некоторого класса, он не будет работать (если не окончательный).

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