Я до сих пор не могу понять, как метод onProgress может вызвать мертвую блокировку
Давайте представим, что у нас есть ProgressListener
реализация
Downloader downloader = new Downloader();
downloader.addListener(new ProgressListener(){
public void onProgress(int n) {
// do something
Thread th = new Thread(() -> downloader.addListener(() -> {});
th.start();
th.join();
}
});
downloader.updateProgress(10);
Первый вызов addListener
будет успешным. Когда вы вызываете updateProgress
, метод onProgress
будет запущен. Когда срабатывает onProgress
, он никогда не завершится, так как вызывается метод addListener
(блокировка по методу синхронизации), пока onProgress
все еще получает блокировку. Это приводит к тупику.
Теперь этот пример глуп, поскольку на самом деле не нужно пытаться создать тупик, но сложные пути кода и общая логика могут легко привести к некоторой форме тупика. Суть в том, чтобы никогда не ставить себя в такое положение
почему клонирование списка слушателей может избежать проблемы.
Вы хотите выполнить синхронизацию при доступе к коллекции, потому что она используется и видоизменяется несколькими потоками. Создавая клон, вы больше не позволяете другим потокам изменять свою коллекцию (локальный клон потока) и можете безопасно перемещаться.
Вы все еще синхронизируете при чтении с клоном, но выполнение onProgress
происходит за пределами synchronization
. Когда вы сделаете это, мой пример, который я перечислил, никогда не будет тупиковым, поскольку только один поток будет получать монитор Downloaded
.