Альтернатива финализатору Java

Я реализую службу блокировки в распределенной системе, используя Mysql GET_LOCK< /а>. После вызова моего метода getLock(), если клиент получает блокировку, я делаю запись в БД и удаляю запись, когда блокировка снимается.

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

Одним из способов было бы использовать метод finalize для моего объекта блокировки, чтобы освободить его при вызове finalize. Однако это не идеально, добавляет сложности и устарело в Java 9. Я читал о фантомных ссылках, которые лучше, чем финализаторы, но уровень их сложности также высок. Я держу его в качестве последнего средства.

Есть ли более простой, менее зависимый от JVM способ справиться с этим вариантом использования?


person dhamu    schedule 29.06.2020    source источник
comment
Является ли Java вашей основной системой? Если да, то у него богатая подсистема блокировки. Зачем вам нужно использовать БД для этих целей?   -  person PM 77-1    schedule 30.06.2020
comment
Неплохо подмечено. Однако, к сожалению, мы используем java 7, и в настоящее время для нашего варианта использования достаточно mysql get_lock, и на данный момент его невозможно изменить.   -  person dhamu    schedule 30.06.2020
comment
есть Cleaner API, но только начиная с java-9.   -  person Eugene    schedule 30.06.2020


Ответы (1)


Не делайте этого. Проблемы перевешивают преимущества.

Независимо от того, используете ли вы финализацию, эталонный API или Cleaner (который основывается на эталонном API), попытка использовать жизненный цикл объекта для управления блокировкой создаст еще больше проблем.

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

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

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

Чтобы предотвратить ранний сбор, вам нужно что-то вроде Reference.reachabilityFence(lockObject), но когда программист забывает выполнить требуемое действие разблокировки, насколько вероятно, что он не забудет вставить необходимое ограничение доступности ? Вместо этого им было бы проще вставить необходимое действие разблокировки.

Любая попытка решить эту проблему будет далеко не простой, но и не даст гарантий, которые стоили затраченных усилий. Вам лучше настоятельно напомнить пользователям вашего класса блокировки о необходимости его разблокировки. Рассмотрите возможность реализации AutoCloseable и рекламировать его использование в try-with-resource.

person Holger    schedule 30.06.2020
comment
Спасибо @holger за подробное объяснение. - person dhamu; 01.07.2020