Запретить запуск нескольких экземпляров Java-приложения - PullRequest
17 голосов
/ 12 августа 2011

Я хочу запретить пользователю запускать мое java-приложение несколько раз параллельно.

Чтобы предотвратить это, я создал файл блокировки при открытии приложения и удаляю файл блокировки при закрытии приложения.

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

Как я могу убедиться, что метод блокировки файла работает или какой другой механизм я могу использовать?

Ответы [ 9 ]

12 голосов
/ 12 августа 2011

Подобное обсуждение на http://www.daniweb.com/software-development/java/threads/83331

Свяжите ServerSocket. Если не удается выполнить привязку, прервите запуск. Поскольку ServerSocket может быть привязан только один раз, запускать могут только отдельные экземпляры программы.

А прежде чем спросить, нет. То, что вы привязываете ServerSocket, не означает, что вы открыты для сетевого трафика. Это вступает в силу только после того, как программа начинает «прослушивать» порт с помощью accept ().

7 голосов
/ 12 августа 2011

Я вижу два варианта, которые вы можете попробовать:

  1. Использовать Java завершающий хук
  2. Ваш файл блокировки должен содержать основной номер процесса. Процесс должен существовать, когда вы запускаете другой экземпляр. Если он не найден в вашей системе, вы можете предположить, что блокировку можно снять и перезаписать.
4 голосов
/ 10 октября 2017

Вы можете использовать FileLock, он также работает в средах, где несколько пользователей совместно используют порты:

String userHome = System.getProperty("user.home");
File file = new File(userHome, "my.lock");
try {
    FileChannel fc = FileChannel.open(file.toPath(),
            StandardOpenOption.CREATE,
            StandardOpenOption.WRITE);
    FileLock lock = fc.tryLock();
    if (lock == null) {
        System.out.println("another instance is running");
    }
} catch (IOException e) {
    throw new Error(e);
}

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

4 голосов
/ 12 августа 2011

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

3 голосов
/ 05 апреля 2018

Создание сокета сервера, привязанного к конкретному порту с экземпляром ServerSocket при запуске приложения, является прямым путем.
Обратите внимание, что ServerSocket.accept() блокирует, поэтому запуск его в своем собственном потоке имеет смысл, чтобы не блокировать основной Thread.

Вот пример с исключением, выданным при обнаружении:

public static void main(String[] args) {       
    assertNoOtherInstanceRunning();
    ...     // application code then        
}

public static void assertNoOtherInstanceRunning() {       
    new Thread(() -> {
        try {
            new ServerSocket(9000).accept();
        } catch (IOException e) {
          throw new RuntimeException("the application is probably already started", e);
        }
    }).start();       
}
2 голосов
/ 14 января 2014

Вы можете создать серверный сокет как

       new ServerSocket(65535, 1, InetAddress.getLocalHost());

в самом начале вашего кода.Затем, если в основном блоке обнаружено исключение AddressAlreadyInUse, вы можете отобразить соответствующее сообщение.

1 голос
/ 25 декабря 2015

Вы можете написать что-то вроде этого.

Если файл существует, попробуйте удалить его. если он не может удалить. Можно сказать, что приложение уже запущено.

Теперь создайте тот же файл снова и перенаправьте sysout и syserr.

Это работает для меня

1 голос
/ 12 августа 2011

.. какой другой механизм я мог бы использовать?

Если приложение. имеет графический интерфейс, который можно запустить с помощью Java Web Start . API JNLP , предоставляемый для веб-старта, предлагает SingleInstanceService. Вот мое демо. SingleInstanceService.

0 голосов
/ 12 октября 2017

В классе File уже доступны методы java для достижения того же.Методом является deleteOnExit (), который обеспечивает автоматическое удаление файла при выходе из JVM.Тем не менее, он не предназначен для принудительного завершения.Следует использовать FileLock в случае принудительного завершения.

Для более подробной проверки, https://docs.oracle.com/javase/7/docs/api/java/io/File.html

Таким образом, фрагмент кода, который может быть использован в основном методе, может иметь вид:

public static void main(String args[]) throws Exception {

    File f = new File("checkFile");

    if (!f.exists()) {
        f.createNewFile();
    } else {
        System.out.println("App already running" );
        return;
    }

    f.deleteOnExit();

    // whatever your app is supposed to do
    System.out.println("Blah Blah")
}
...