Важнейшим компонентом проблемы безопасности потоков является не только взаимное исключение. Вполне возможно завершить атомное обновление состояния объекта, т. Е. Осуществить переход состояния, который оставляет объект в допустимом состоянии с неизменными его инвариантами, но все же оставить объект уязвимым, если его ссылки все еще публикуются до недостоверного или неполного отлаживаемых клиентов.
В примере проводке:
public synchronized boolean putIfAbsent(E x) {
boolean absent = !list.contains(x);
if (absent)
list.add(x);
return absent;
}
Код потокобезопасен, а W.M. указал. Но у нас нет никаких гарантий относительно самого x
и где у него могут быть ссылки, которые еще хранятся в другом коде. Если такие ссылки действительно существуют, другой поток может изменять соответствующие элементы в вашем списке, превзойдя ваши усилия по защите инвариантов объектов в списке.
Если вы принимаете элементы этого списка из кода клиента, которому вы не доверяете или не знаете, хорошей практикой было бы сделать защитную копию x, а затем добавить ее в свой список. Аналогичным образом, если вы вернете объект из своего списка в другой код клиента, создайте защитную копию и верните ее, чтобы убедиться, что ваш список остается потокобезопасным.
Кроме того, список должен быть полностью инкапсулирован в классе. Имея это общедоступным, клиентский код в любом месте может свободно обращаться к элементам и не позволяет вам защитить состояние объектов в списке.
Возможно, это ... Кто сказал, что это не потолочный сейф? Получили ли вы состояние гонки или тупик? –
Это был пример в Java Concurrency In Practice, который не мог понять, почему этот пример был указан как небезопасный. – Ullas
Я немного удивлен, что они не объяснили, почему ... –