29

ユーザーがJavaアプリケーション(WebStart Swingアプリ)を複数回起動しないようにする必要があります。したがって、アプリケーションがすでに実行されている場合は、アプリケーションを再起動したり、警告を表示したり、再度閉じたりすることはできません。

これを達成するための便利な方法はありますか?ポートをブロックするか、ファイルにsthを書き込むことを考えました。しかし、うまくいけば、いくつかのシステムプロパティまたはJVMにアクセスできますか?

ところで。ターゲットプラットフォームは、Java1.5を搭載したWindowsXPです。

4

9 に答える 9

37

アプリケーションを起動するときにリッスンするポートを開くという提案が最善のアイデアだと思います。

実行は非常に簡単で、アプリケーションを閉じるときにクリーンアップすることを心配する必要はありません。たとえば、ファイルに書き込んだ後、誰かがタスクマネージャを使用してプロセスを強制終了した場合、ファイルは削除されません。

また、私が正しく覚えていれば、JVM内からJavaプロセスのPIDを取得する簡単な方法はないので、PIDを使用してソリューションを作成しようとしないでください。

このような何かがトリックを行う必要があります:

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);
  }
}

このサンプルコードは明示的にバインドされ127.0.0.1、ファイアウォールの警告を回避する必要があります。このアドレスのトラフィックはローカルシステムからのものである必要があるためです。

ポートを選択するときは、既知のポートのリストに記載されているポートを避けるようにしてください。理想的には、競合が発生した場合に、使用するポートをファイル内またはコマンドラインスイッチを介して構成可能にする必要があります。

于 2009-05-28T11:32:15.243 に答える
26

質問にはWebStartが使用されていると記載されているため、明らかな解決策はを使用することjavax.jnlp.SingleInstanceServiceです。

このサービスは1.5で利用できます。1.5は現在、耐用年数の終わりのほとんどの期間であることに注意してください。Java SE 6を入手してください!

于 2009-05-28T12:33:58.863 に答える
3

より良いアイデアはファイルロックを使用することだと思います(かなり古いアイデア:))。Java 1.4以降、ファイルロックを可能にする新しいI/Oライブラリが導入されました。

アプリケーションが起動すると、ファイルのロックを取得しようとします(または、存在しない場合はファイルを作成します)。アプリケーションが終了すると、ロックが解除されます。アプリケーションがロックを取得できない場合、アプリケーションは終了します。

ファイルロックを行う方法の例は、たとえばJavaDevelopersAlmanacにあります。

Java Web Startアプリケーションまたはアプレットでファイルロックを使用する場合は、アプリケーションまたはアプレットを歌う必要があります。

于 2009-05-28T12:35:06.800 に答える
2

JUniqueライブラリを使用できます。シングルインスタンスJavaアプリケーションの実行をサポートし、オープンソースです。

http://www.sauronsoftware.it/projects/junique/

単一インスタンスのJavaアプリケーションを実装する方法の私の完全な回答も参照してください。

于 2016-11-23T11:32:57.610 に答える
1

C ++でも、カーネルミューテックスオブジェクトを作成し、起動時にそれを探すことで同じことを行います。利点は、ソケットを使用する場合と同じです。つまり、プロセスが停止/クラッシュ/終了/強制終了されると、mutexオブジェクトがカーネルによってクリーンアップされます。

私はJavaプログラマーではないので、Javaで同じようなことができるかどうかわかりません。

于 2009-05-28T12:06:46.890 に答える
1

クロスプラットフォームのAppLockクラスを作成しました。

http://mixeddev.info/articles/2015/02/01/run-single-jvm-app-instance.html

ファイルロック技術を使用しています。

アップデート。2016-10-14で、maven / gradle https://github.com/jneat/jneatと互換性のあるパッケージを作成し、ここで説明しましたhttp://mixeddev.info/articles/2015/06/01/synchronize-different -jvm-instances.html

于 2012-07-20T11:08:25.710 に答える
0

レジストリを使用することもできますが、これはJavaのような高級言語を使用するという目的を中途半端に無効にします。少なくともターゲットプラットフォームはwindows=D

于 2009-05-28T11:31:39.300 に答える
0

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);
}
于 2017-09-12T14:21:47.370 に答える
-1

私はこの質問をたくさん見てきましたが、ファイアウォールと衝突したり、ソケットに侵入したりする機会をとらない、プラットフォームに依存しない方法で同じ問題を解決しようとしていました。

だから、これが私がしたことです:

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;
    }
}

ロックファイルパスにSystem.getProperty( "java.io.tmpdir")を使用すると、常に同じ場所にロックを作成できます。

次に、プログラムから次のように呼び出します。

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);
    }
}

そして、それは私のためにそれをします。これで、プログラムを強制終了してもロックファイルは削除されませんが、プログラムのPIDをロックファイルに書き込み、lock()メソッドでそのプロセスがすでに実行されているかどうかを確認することで、これを解決できます。これは、興味のある人のための評価として残されています。:)

于 2014-03-06T12:56:06.773 に答える