Определяем порядок захвата монитора

  • 14
  • Недоступна
Реализуй логику метода isLockOrderNormal, который должен определять: соответствует ли порядок synchronized блоков в методе someMethodWithSynchronizedBlocks - порядку передаваемых в него аргументов. В случае, если сначала происходит синхронизация по o1, а потом по o2, метод должен вернуть true. Если
Вы не можете решать эту задачу, т.к. не залогинены.
Комментарии (123)
  • популярные
  • новые
  • старые
Для того, чтобы оставить комментарий вы должны авторизоваться
Иван Сапронов29 уровень, Ставрополь
18 июня, 09:57
Вот же ж блин! Запорол одну попытку по глупейшей причине: в качестве параметра метода
solution.someMethodWithSynchronizedBlocks(o1, o2);
вместо "o2" написал "02" (ноль два) ! Рука-лицо... При этом код, сволочь, спокойно компилировался в ходе проверки и даже выдал тру ))
Сергей30 уровень, Одесса
13 мая, 05:49
Долго разбирался с непредсказуемым поведением программы. В одних случаях все работало корректно, в следующий момент результат работы не удовлетворял валик. В итоге решил задачу с третьей попытки. Однако, потом понял, что это просто случайность и на той технике, на которой тестировался мой код просто совпали все звезды для этого. К какому выводу я пришёл : потоки работали асинхронно, и чтобы хоть как то добиться правильного и стабильного результата, необходимо было их синхронизировать. Первым что пришло в голову, избавиться от задержек времени и заставить программу запускать потоки последовательно один за другим. Поэтому решил не использовать sleep. В итоге алгоритм таков : 1. Создаём блок синхронайз монитора о1 и все последующие пункты выполняем в нем. Тем самым мы избавляемся от трех потоков (нитей). Достаточно только двух. 2. Запускаем поток t1, в котором вызываем метод someMethodWithSynchronizedBlocks. 3. Синхронизируем последовательность выполнения потока t1, вызвав у него метод join, в котором указываем задержку 1 мс. Теперь мы уверены, что поток 1 запущен. 4. Запускаем поток t2, который просто блокирует монитор о2 в попытке. 5. Повторяем п.3 для потока t2. Проверяем статус второго потока, по аналогии с комментариями ниже. 6. Дополнительно можем прервать поток 2. 7. На этом завершается блок синхронайз о1. Выйдя из блока синхронайз о1, мы опускаем блокировку объекта и работа передаётся потоку t1, так как он следующим заблокировал монитор о1. t1 завершает работу. В случае, когда порядок объектов в проверяемом методе является не естественным, то управление передаётся потоку t2, так как он остался ещё в режиме блокировки. Поэтому п.6 является необязательным. Данный алгоритм гарантирует стабильность при выполнении кода. К тому же можно управлять оперативностью получения результата, играясь со значениями параметров метода join. В моем решении валик принял код с такими данными join(0, 10). Но для безопасности лучше ставить большее значение.
Ivan29 уровень
6 июня, 12:33
Можно обойтись и одной нитью. В блоках использовать статусы нити, там где запускаем нить Thread.State.BLOCKED, там где используем join Thread.State.TERMINATED. У меня была ошибка потому что в созданной нити вызывал метод
solution.someMethodWithSynchronizedBlocks(o2, o1);
поменял местами объекты
solution.someMethodWithSynchronizedBlocks(o1, o2);
валидатор принял решение
Вячеслав Е.29 уровень, Москва
18 июня, 10:25
Огромное спасибо за коммент! Все очень понятно объяснил!
Даниил31 уровень
3 мая, 12:03
Когда прочитал задание, то вообще не мог представить как это решить. По советам ниже прочитал подсказку "Даня Кельвич" от 11 июля 2017. Так и не понял как точно это повторить. В итоге используя его принцип и потратив около часа наблюдений за поведением потоков сделал результат метода правильным в независимости от "случая" (то есть бывало что нити иногда выдавали другие значения состояния в зависимости от распределения им процессорного времени и т.п.), но вот проблема в том что я так и не придумал сбособ что бы программа завершалась... Она просто зависала от созданного мной дэдлока в слечае результата false, но зато метод отрабатывал правильно и возвращал правильный результат. Валидатор это чудо принял... P.S. У кого получилось решить задание и при этом программа корректно сама завершалась - дайте знать пожалуйста, очень любопытно... И демоны тут не выход так как в нашем случае можно написать так что бы поток прекращался вместе с главным методом, но что если у нас целая программа и она должна дальше работать?
gts32039 уровень, Харьков
24 марта, 13:06
Если метод someMethodWithSynchronizedBlocks() переопределен, (только в этом случае может измениться порядок synchronized блоков), то все эти проверки на deadlock абсолютно бессмысленны, т. к. в переопределенном методе может быть только один synchronized(о1) блок или только один synchronized(о2) блок или вообще может не быть никаких synchronized блоков. Т. о. если при каких-то там "проверках" не наступает deadlock, то это совсем не значит что синхронизация в методе someMethodWithSynchronizedBlocks() происходит сначала по объекту o1, а потом по o2. Следовательно, значение true, возвращаемое методом isLockOrderNormal() в этих случаях не будет иметь того смысла, который предписывается ему условием задачи. Грубое нарушение логики, допущенное автором задачи, делает несостоятельным само существование метода isLockOrderNormal(), который способен возвращать всего два значения.
Kazbek35 уровень, Москва
17 марта, 21:17
Добавил подмену System.out чтобы в консоль не выводился текст лишний
S3R3N1TY36 уровень, Санкт-Петербург
15 марта, 21:19
В начале (до комментов) пробовал решить через рефлексию. 1. Получил метод в котором нужно проверить порядок:
Method method = solution.getClass().getDeclaredMethod("someMethodWithSynchronizedBlocks",Object.class,Object.class);
2. Получил параметры метода. И потом думал как их дальше найти в синхронайз-блоках. Но такого способа движения по коду не нашел.
Dmitry Deryuga29 уровень
5 марта, 10:56
Не удаляйте в нитях строку "System.out.println(obj1 + " " + obj2);" Задача требует вывод в консоль только результата метода "isLockOrderNormal", но валику на это "все равно"...
Дмитрий К.33 уровень, Иркутск
4 марта, 06:14
немного не понятно ... предположим что кто-то унаследовался от нашего класса Solution и переписал метод так
synchronized (obj2) {
            synchronized (obj1) {
                System.out.println(obj1 + " " + obj2);
            }
        }
Мы нашим методом isLockOrderNormal проверили что блокировка объектов происходит не правильно и вернули false, но наши две нити так и повисли в deadlock-е .... надо в условии задачи еще предусмотреть чтобы две нити завершились исправно ... а как выйти из дедлока без применения сторонних методов блокировки по Object или Lock ??
Iosif Futerman31 уровень, Екатеринбург
1 апреля, 06:54
Цель задачи, дать представление и применить состояния потока, а не предпринимать действия по разруливанию ситуации
Даниил31 уровень
3 мая, 12:09
Тот же вопрос возник на счёт "а как разрулить этот дэдблок и всё работало правильно", но так ответа и не нашёл. Даже задал вопрос на этот счёт, может что что-то дельное предложит...
Andrii Gorshunov41 уровень
5 февраля, 00:02
Решилась спустя час по подсказке Даня Кельвич (внизу)
Денис Дворецкий38 уровень, Минск
24 января, 17:11
Маааааленькая подсказка ;) Для проверки своего решения меняйте местами объекты в synchronized блоках метода someMethodWithSynchronizedBlocks. Я надеюсь станет понятнее чего от вас хотят :)