Я разрабатываю Java-приложение. И я хотел, чтобы пользователь не запускал одновременно больше экземпляров одного и того же Java-приложения. Я использовал библиотеку блокировки приложений JUnique для Java, и она отлично работает. Но имеет серьезную проблему, когда он падает.
Приложение не может быть запущено, если оно сработает, оно просто возвращает AlreadyLockedException. Код, который я использовал для блокировки моего приложения, приведен ниже.
public static boolean isRunning() {
boolean alreadyRunning = false;
try {
JUnique.acquireLock(appId);
alreadyRunning = false;
} catch (AlreadyLockedException e) {
logger.error("Unable to acquire lock. There is an instance already running");
alreadyRunning = true;
} catch (Throwable t) {
logger.error("Unable to acquire lock. ", t);
}
return alreadyRunning;
}
И код для освобождения моего замка:
public static void release() {
try {
JUnique.releaseLock(appId);
} catch (Throwable t) {
logger.error("Error releasing the lock", t);
}
}
Я могу использовать метод release() для решения ожидаемых сбоев. Но реальная проблема возникает, когда приложение неожиданно появляется во время выполнения. Приложение прекращается без освобождения приобретенной блокировки для приложения.
Как мы можем освободить блокировку JUnique, если приложение неожиданно выйдет из строя?
Это ошибка дизайна JUnique (последняя версия, которую я нашел здесь). Просто нет поддержки для случая сбоя компьютера (BSOD, прерывание питания). Предполагается, что ShutdownHook
(который удаляет блокировки, см. JUnique.java) всегда выполняется. Недостаток очевидна в api-docs releaseLock
:
"Обратите внимание, что блокировка может быть показана только той же JVM, которая ранее ее приобрела. Если данный идентификатор не соответствует блокировке, принадлежащей текущей JVM, никаких действий не будет предпринято".
Но нет метода forceReleaseLock(String id)
который, в свою очередь, означает, что после сбоя компьютера приложение больше не может быть запущено.
В таких случаях довольно часто сообщать пользователю диалог с сообщением "Приложение уже запущено" и кнопкой "ОК", которая показывает окно запущенного приложения. В этом случае вы можете добавить кнопку "Нет, это не так" и при нажатии:
JUnique.sendMessage
возвращает значение null.new File(System.getProperty("user.home"), ".junique");
(LOCK_FILES_DIR, см. JUnique.java) или что-то подобное, что менее грубо.UncaughtExceptionHandler
улучшает , что угодно: ShutdownHook
зарегистрирован JUnique уже обеспечивает блокировку удаляется перед нанесением / JVM останавливается (без сбоев).
AlreadyLockedException
трассировку стека этогоAlreadyLockedException
.Thread.UncaughtExceptionHandler