Вопрос или проблема
Почему-то это решение для предотвращения запуска нескольких экземпляров приложения больше не работает – в чем проблема?
Я ожидаю, что при повторном запуске этого приложения будет выводиться: “другой экземпляр запущен” и оно завершится с ошибкой, но этого не происходит. Второй экземпляр работает так же, как и первый.
import java.io.File;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.file.StandardOpenOption;
public class JustOneTest {
public static void main(String[] args) {
runCheck();
while (true) {
try {
System.out.print(".");
Thread.sleep(5 * 60);
} catch (Exception e) {
e.printStackTrace();
}
}
}
private static void runCheck() {
System.out.println("начинаем проверку: приложение запущено");
final File file = new File(System.getProperty("user.home"), "khf.lock");
try {
FileLock lock;
try (FileChannel fc = FileChannel.open(file.toPath(),
StandardOpenOption.CREATE,
StandardOpenOption.WRITE)) {
lock = fc.tryLock();
}
if (lock == null) {
System.out.println("другой экземпляр запущен");
throw new Error("другой экземпляр запущен");
}
System.out.println(lock);
// вывод: sun.nio.ch.FileLockImpl[0:9223372036854775807 exclusive invalid]
} catch (IOException e) {
throw new Error(e);
}
System.out.println("проверка завершена");
}
}
Ответ или решение
Проблема с тем, что ваши экземпляры Java-приложения могут запускаться одновременно, заключается в том, как работает блокировка файлов с помощью FileLock
. Хотя ваш код выглядит в целом правильно, в нем есть некоторые нюансы, которые могут мешать корректному функционированию механизма блокировки.
Давайте разберемся с проблемами и возможными решениями:
-
Отсутствие правильной блокировки:
В вашем коде блокировка создается и закрывается сразу после вызоваtryLock()
, что не сохраняет блокировку, посколькуFileChannel
закрывается до того, как блокировка может быть использована. Вам нужно держатьFileChannel
открытым, пока блокировка активна. Вот как можно исправить это:private static void runCheck() { System.out.println("start check: is app running"); final File file = new File(System.getProperty("user.home"), "khf.lock"); FileChannel fc = null; FileLock lock = null; try { fc = FileChannel.open(file.toPath(), StandardOpenOption.CREATE, StandardOpenOption.WRITE); lock = fc.tryLock(); if (lock == null) { System.out.println("another instance is running"); throw new Error("another instance is running"); } System.out.println(lock); } catch (IOException e) { throw new Error(e); } finally { // Закрываем канал и блокировку в конце try { if (lock != null) { lock.release(); } if (fc != null) { fc.close(); } } catch (IOException e) { e.printStackTrace(); } } System.out.println("start check completed"); }
-
Проблемы с доступом к файлу:
Убедитесь, что у вашего приложения есть права на создание и запись в файл блокировки в указанной директории. Если ваше приложение работает от имени пользователя, у которого нет прав на запись вuser.home
, блокировка не сработает. -
Платформозависимость:
Имейте в виду, что поведение блокировки файлов может различаться в зависимости от операционной системы. Например, блокировки, установленные на одном потоке, могут не работать на других потоках в некоторых средах выполнения. Поэтому убедитесь, что вы тестируете это в подходящей среде. -
Закрытие ресурсов:
Убедитесь, что ресурсы закрываются корректно, даже в случае возникновения исключений. Использование блоковtry-with-resources
для файловых каналов и блокировок может помочь с правильным управлением ресурсами.
Следуя данным рекомендациям, ваше приложение должно должным образом предотвращать запуск нескольких экземпляров. Убедитесь также, что вы тестируете его в чистом окружении, чтобы исключить влияние других экземпляров или процессов, которые могут работать с тем же файлом.