Como permitir executando apenas uma instância de um programa em Java em um momento?
-
06-09-2019 - |
Pergunta
Eu preciso impedir os utilizadores de iniciar a minha aplicação Java (WebStart balanço app) várias vezes. Então, se o aplicativo já está em execução, não deve ser possível para iniciá-lo novamente ou mostrar um aviso / ser fechada novamente.
Existe alguma maneira conveniente para conseguir isso? Eu pensei sobre o bloqueio de uma porta ou escrever sth para um arquivo. Mas espero que você pode acessar algumas propriedades do sistema ou a JVM?
btw. plataforma de destino é Windows XP com Java 1.5
Solução
Eu acho que a sua sugestão de abrir uma porta para ouvir quando você iniciar seu aplicativo é a melhor idéia.
É muito fácil de fazer e você não precisa se preocupar em limpá-lo quando você fecha o aplicativo. Por exemplo, se você escrever para um arquivo mas alguém, em seguida, mata os processos usando o Gerenciador de Tarefas do arquivo não vai ficar excluído.
Além disso, se bem me lembro há nenhuma maneira fácil de obter o PID de um processo Java de dentro da JVM então não tente e formular uma solução utilizando PIDs.
Algo como isso deve fazer o truque:
private static final int PORT = 9999;
private static ServerSocket socket;
private static void checkIfRunning() {
try {
//Bind to localhost adapter with a zero connection queue
socket = new ServerSocket(PORT,0,InetAddress.getByAddress(new byte[] {127,0,0,1}));
}
catch (BindException e) {
System.err.println("Already running.");
System.exit(1);
}
catch (IOException e) {
System.err.println("Unexpected error.");
e.printStackTrace();
System.exit(2);
}
}
Este código de exemplo explicitamente liga a 127.0.0.1
que deve evitar quaisquer avisos de firewall, como qualquer tráfego neste endereço deve ser a partir do sistema local.
Ao escolher uma tentativa porta para evitar mencionado na href="http://www.iana.org/assignments/port-numbers" lista do conhecido Portos . Idealmente, você deve fazer a porta usada configurável em um arquivo ou através de uma opção de linha de comando em caso de conflitos.
Outras dicas
Como os questão afirma que WebStart está sendo usado, a solução óbvia é usar javax.jnlp.SingleInstanceService
.
Este serviço está disponível em 1,5. Note-se que 1.5 é atualmente a maior parte do caminho através de seu final do período de vida útil. Obter com o Java SE 6!
Eu acho que a melhor idéia seria usar bloqueio de arquivo (bastante uma ideia antiga :)). Desde Java 1.4 uma nova biblioteca de I / O foi introduzido, que permite o bloqueio de arquivos.
Uma vez que o aplicativo é iniciado tenta trava adquirida em um arquivo (ou criá-lo se não existe), quando o aplicativo é encerrado o bloqueio é relased. Se a aplicação não pode adquirir um bloqueio, ele sai.
O exemplo de como fazer o bloqueio de arquivos é, por exemplo, em Java Developers Almanac .
Se você quiser usar o bloqueio de arquivos no aplicativo Java Web Start ou um applet que você precisa para cantar o aplicativo ou o applet.
Nós fazemos o mesmo em C ++, criando um objeto mutex kernal e olhando para ele no arranque. As vantagens são o mesmo que usar um encaixe, ou seja, quando o processo de fieiras / falhas / saídas / é morto, o objecto de exclusão mútua é limpo pelo kernel.
Eu não sou um programador Java, então eu não tenho certeza se você pode fazer o mesmo tipo de coisa em Java?
Você pode usar a biblioteca JUnique. Ele fornece suporte para a execução de aplicativos Java de instância única e é open-source.
http://www.sauronsoftware.it/projects/junique/
Veja também a minha resposta completa em Como implementar um aplicativo Java única instância?
Eu tenho criar a classe plataforma AppLock cruz.
http: //rumatoest.blogspot .com / 2015/01 / howto-run-only-single-java-application.html
É utilizando a técnica de bloqueio de arquivo.
Update. No 2016/10/14 Eu criei pacote compatível com maven / Gradle https://github.com/jneat/ jneat e explicou-lo aqui http: / /rumatoest.blogspot.com/2015/06/synchronize-code-over-multiple-jvm.html
Você pode usar o registro, embora esta derrota halfheartedly o propósito de usar uma linguagem de alto nível como Java. Pelo menos sua plataforma de destino é janelas = D
Tente JUnique:
String appId = "com.example.win.run.main";
boolean alreadyRunning;
try {
JUnique.acquireLock(appId);
alreadyRunning = false;
} catch (AlreadyLockedException e) {
alreadyRunning = true;
}
if (alreadyRunning) {
Sysout("An Instance of this app is already running");
System.exit(1);
}
Eu vi tantos de esta pergunta e eu estava olhando para resolver o mesmo problema de uma forma independente de plataforma que não tem a chance de colidir com firewalls ou entrar em coisas socket.
Então, aqui está o que eu fiz:
import java.io.File;
import java.io.IOException;
/**
* This static class is in charge of file-locking the program
* so no more than one instance can be run at the same time.
* @author nirei
*/
public class SingleInstanceLock {
private static final String LOCK_FILEPATH = System.getProperty("java.io.tmpdir") + File.separator + "lector.lock";
private static final File lock = new File(LOCK_FILEPATH);
private static boolean locked = false;
private SingleInstanceLock() {}
/**
* Creates the lock file if it's not present and requests its deletion on
* program termination or informs that the program is already running if
* that's the case.
* @return true - if the operation was succesful or if the program already has the lock.<br>
* false - if the program is already running
* @throws IOException if the lock file cannot be created.
*/
public static boolean lock() throws IOException {
if(locked) return true;
if(lock.exists()) return false;
lock.createNewFile();
lock.deleteOnExit();
locked = true;
return true;
}
}
Usando System.getProperty ( "java.io.tmpdir") para o caminho lockfile garante que você sempre irá criar o seu bloqueio no mesmo lugar.
Em seguida, a partir do programa que você acabou de chamar algo como:
blah blah main(blah blah blah) {
try() {
if(!SingleInstanceLock.lock()) {
System.out.println("The program is already running");
System.exit(0);
}
} catch (IOException e) {
System.err.println("Couldn't create lock file or w/e");
System.exit(1);
}
}
E que faz isso por mim. Agora, se você matar o programa não irá apagar o arquivo de bloqueio, mas você pode resolver isso por escrito PID do programa na lockfile e fazer a verificação método lock () se esse processo já está em execução. Este é deixado como um assingment para qualquer pessoa interessada. :)