- ベストアンサー
スタンドアロンJavaプログラム(Swing)の複数起動の抑止方法
SwingでスタンドアロンのJavaプログラムを作成しています。 Executable JARファイルとして、ダブルクリックにより起動するのですが、一度起動した後もう一度ダブルクリックすると同じプログラムが別に起動してしまいます。 JDK1.5、OSはWindowsが対象です。 複数起動できないようにする方法はありますでしょうか? よろしくお願いします。 ※ファイルに起動フラグを書出すという方法は考えてみましたが、クラッシュ(異常終了)したときに起動不可能になるためこの方法は使用できませんでした。
- みんなの回答 (2)
- 専門家の回答
質問者が選んだベストアンサー
私が思いつく一般的と思われる方法は2つあります。 (1)WindowsのMutexを利用する方法 WinAPIのCreateMutex()を利用し、適当な名前のMutexを作成します。 Mutex作成の成功・失敗でプログラムの二重起動を判定します。 Windowsでは一般的な方法ですので情報は手に入れやすいと思います。 ただし、Java以外の言語でプログラムを書く必要があります。 (2)ファイルチャネルのロックを利用する方法 あくまでJavaのみでということでしたら、ファイルチャネルのロックを利用する方法があります。 説明しにくいのでサンプルコードを書きます。(あくまでサンプルなので、実際に使う場合はよくテストしてください。) 仮にVMが異常終了した場合でもロックはおそらく開放されます。(Windowsがプロセスの終了を検知するため) 万が一開放されなかった場合でも、Windowsの再起動で開放されます。 -------------------------------------------------------------------------------- import java.io.File; import java.io.FileOutputStream; import java.nio.channels.FileChannel; import java.nio.channels.FileLock; public class Sample { public static void main(String[] args) { //起動チェック final FileOutputStream fos = new FileOutputStream(new File("lock")); final FileChannel fc = fos.getChannel(); final FileLock lock = fc.tryLock(); if (lock == null) { //既に起動されているので終了する return; } //ロック開放処理を登録 Runtime.getRuntime().addShutdownHook( new Thread() { public void run() { if (lock != null && lock.isValid()) { lock.release(); } fc.close(); fos.close(); } } ); //処理を続行 } } -------------------------------------------------------------------------------- それから、#1さんのソケットを使う方法には以下の問題点があります。 ・メッセージの送受信(起動チェック)とリスン開始(ロック)の処理が分離されている (タイミング次第で多重起動可能) ・起動されていない場合(正常系)と何らかのエラーで返信が返ってこない場合(異常系)の区別ができない ・返信が無いというのはタイムアウトになるということであり、起動時間が多少長くなる 個人用のツールならともかく、業務システムに使用するのはお勧めできません。 #念の為に書いておきますが、回答を批判しているわけではありません。
その他の回答 (1)
- TAKATON
- ベストアンサー率62% (17/27)
>※ファイルに起動フラグを書出すという方法は考えてみましたが、 >クラッシュ(異常終了)したときに起動不可能になるためこの方法は使用 >できませんでした。 ならば、ソケット通信を使って、二重起動を監視してみてはいかがでしょうか? アプリケーション起動時にソケット通信を使って、他のアプリケーションへ メッセージを送信する。送信メッセージに対する返信がなければ、自分しか 起動されていないのでOK。返信があればNG。 自分しか起動されていないことがわかったら、次に、他のアプリケーションが 二重起動されるのを防ぐために、決められたポート番号でリスンする。 このポート番号に他のアプリケーションからメッセージが送信されてきた場合は、 既に起動済みである旨のメッセージを返す。 ただし、気をつけなければならないのは、決められたポートでリスンする処理は、 アプリのメインスレッドとは別のスレッドで行う必要があるということです。
お礼
ご回答ありがとうございます。 今回はNo.2にgimmickさんから頂いた回答の「(2)ファイルチャネルのロックを利用する方法」を使うことにしました。 ソケット通信を使うことまでは気付きませんでした。 将来、別の機会に使うこともあるかもしれないので、動作確認のために実装を試みてみました。 その結果分かったことは、リスンのためにServerSocketでポートを開こうとすると、WindowsXP SP2の「Windowsファイアウォール」でブロックされてしまう場合もありそうです。 ※もしかしたらローカルホストに限定すればブロックされないのかもしれませんが、まだ深くは追求していません。 おかげ様で、問題解決方法の視野を広げることができました。 ありがとうございました。
お礼
ご回答ありがとうございます。 今回は、「(2)ファイルチャネルのロックを利用する方法」を使わせていただきます。 java.util.logging.Loggerを使っていて、ファイルのロックの例はすぐ目の前にあったのですが、重複起動チェックに使用することまでは気付きませんでした。 タスクマネージャーでJavaプログラム起動中にjavaw.exeプロセスを終了する確認などもしてみました。 今のところ、この方法で特に問題はなさそうです。 非常に助かりました。ありがとうございました。