2012-04-06 4 views
3

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

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

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

Спасибо!

+0

Можете ли вы опубликовать фрагмент кода? –

+0

Нет, это как 3000+ линий. : -D Это не мой код, заметьте ... –

+1

Из того, что я понимаю, если вам нужно атомарность для всех методов, вам нужно иметь один замок, если вы хотите справедливости, чтобы каждый поток обслуживался процессор в том порядке, в котором они ищут ресурс, вы можете взглянуть на java.util.concurrent.Lock (что гарантирует справедливость, но это связано с накладными расходами). Прочтите http://www.ibm.com/developerworks/java/library/j-jtp09238/index.html и http://www.ibm.com/developerworks/java/library/j-jtp10264/ для лучшего понимания блокировки и происходит - перед заказом в java. –

ответ

2

Если вы изменяете все synchronized блоков (и методы), и все другие блокирующие структуры, я думаю, вы должны быть хорошо - в худшем случае, ваше приложение вырождается к наличию последовательного выполнения. Но если вы только измените некоторые из них, вы можете зайти в тупик. Рассмотрим ситуацию, когда два потока, каждый приобретающие несколько блокировок:

Thread 1: 
    synchronized A 
     synchronized B 

Thread 2: 
    synchronized B 
     synchronized C 

Там нет никакого риска тупика, но если вы замените A и C (но не B) с новым, общим замком, то вы будете иметь :

Thread 1: 
    synchronized L 
     synchronized B 

Thread 2: 
    synchronized B 
     synchronized L 

... классический тупик.

Рассмотрим другого сценария, где замки не обеспечивают тупиковые себя, но вместо этого ТУПИКА класс блокирующего как CountDownLatch:

Thread 1: 
    synchronized A 
     latch L.countDown() 

Thread 2: 
    synchronized B 
     latch L.await() 

В этом случае изменение оба synchronized блоков, чтобы зафиксировать на общий замок выиграл 't вызывают взаимоблокировку между ними, но вызовут тупик, если поток 2 сначала получит блокировку: он будет ожидать счетчик задержек, который никогда не появится, потому что поток 1 заблокирован в точке входа . Этот пример применим и к другим структурам блокировки: семафорам, очередям блокировки и т. Д.

+1

Хорошие точки затвора обратного отсчета - если вы замените блокировки, вы также должны будете освободить блокировку всякий раз, когда вы будете ждать на общем ресурсе, если это уже не сделано. – Alex

+0

Спасибо @yshavit! Однако я не понимаю последний пример. Защелки - это что-то новое для меня, поэтому, если я не вижу задвижек в коде, я не должен беспокоиться, не так ли? Или вы имели в виду что-то более абстрактное от 'latch'? Благодаря! –

+0

@AlbusDumbledore Как заметил @Alex, это действительно любой ресурс, который может блокировать. Многие из классов в java.util.concurrent и java.util.concurrent.locks применяются, но в принципе это могут быть другие ресурсы (например, один фрагмент кода, создающий файл, и еще один фрагмент кода, ожидающий этого файла существовать). – yshavit

0

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

+0

Ну, моя идея заключалась в том, что если я объединю все замки в один, это избавится от проблемы с мертвым замком, жертвуя гранулярностью. Мне интересно, прав ли я. –

+1

@AlbusDumbledore, если блокировка - это единственная синхронизация, которая происходит, тогда вы, вероятно, правы. Просто поймите, что, жертвуя гранулярностью, вы также можете жертвовать своей работой и внедрять возможности для голода. – Alex

+0

Спасибо, Алекс. Я в порядке с возможными проблемами производительности, правда, большинство методов занимают действительно очень малое время (например, менее нескольких мс), и есть небольшая вероятность того, что слишком много потоков одновременно вызовут, но, с другой стороны, сложность кода огромна, и все же я не понимаю, почему они ввели еще большую сложность, используя многие блокировки. Большое спасибо за подтверждение моих мыслей. –

1

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

Должно быть довольно просто написать некоторый код регистрации, который должен прояснить блокировку. Как только вы можете распиливать слои и иметь четкое изображение, должно быть сравнительно просто заменить всю партию одним современным замком, например, ReadWriteLock или аналогичным.

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

Смежные вопросы