【先着1,000名様!】1,000円分をプレゼント!

SwingでスタンドアロンのJavaプログラムを作成しています。
Executable JARファイルとして、ダブルクリックにより起動するのですが、一度起動した後もう一度ダブルクリックすると同じプログラムが別に起動してしまいます。

JDK1.5、OSはWindowsが対象です。

複数起動できないようにする方法はありますでしょうか?
よろしくお願いします。

※ファイルに起動フラグを書出すという方法は考えてみましたが、クラッシュ(異常終了)したときに起動不可能になるためこの方法は使用できませんでした。

このQ&Aに関連する最新のQ&A

A 回答 (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さんのソケットを使う方法には以下の問題点があります。
・メッセージの送受信(起動チェック)とリスン開始(ロック)の処理が分離されている (タイミング次第で多重起動可能)
・起動されていない場合(正常系)と何らかのエラーで返信が返ってこない場合(異常系)の区別ができない
・返信が無いというのはタイムアウトになるということであり、起動時間が多少長くなる

個人用のツールならともかく、業務システムに使用するのはお勧めできません。
#念の為に書いておきますが、回答を批判しているわけではありません。
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。
今回は、「(2)ファイルチャネルのロックを利用する方法」を使わせていただきます。

java.util.logging.Loggerを使っていて、ファイルのロックの例はすぐ目の前にあったのですが、重複起動チェックに使用することまでは気付きませんでした。

タスクマネージャーでJavaプログラム起動中にjavaw.exeプロセスを終了する確認などもしてみました。
今のところ、この方法で特に問題はなさそうです。
非常に助かりました。ありがとうございました。

お礼日時:2006/03/16 01:56

>※ファイルに起動フラグを書出すという方法は考えてみましたが、


>クラッシュ(異常終了)したときに起動不可能になるためこの方法は使用
>できませんでした。

ならば、ソケット通信を使って、二重起動を監視してみてはいかがでしょうか?
アプリケーション起動時にソケット通信を使って、他のアプリケーションへ
メッセージを送信する。送信メッセージに対する返信がなければ、自分しか
起動されていないのでOK。返信があればNG。
自分しか起動されていないことがわかったら、次に、他のアプリケーションが
二重起動されるのを防ぐために、決められたポート番号でリスンする。
このポート番号に他のアプリケーションからメッセージが送信されてきた場合は、
既に起動済みである旨のメッセージを返す。
ただし、気をつけなければならないのは、決められたポートでリスンする処理は、
アプリのメインスレッドとは別のスレッドで行う必要があるということです。
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。
今回はNo.2にgimmickさんから頂いた回答の「(2)ファイルチャネルのロックを利用する方法」を使うことにしました。

ソケット通信を使うことまでは気付きませんでした。
将来、別の機会に使うこともあるかもしれないので、動作確認のために実装を試みてみました。
その結果分かったことは、リスンのためにServerSocketでポートを開こうとすると、WindowsXP SP2の「Windowsファイアウォール」でブロックされてしまう場合もありそうです。
※もしかしたらローカルホストに限定すればブロックされないのかもしれませんが、まだ深くは追求していません。

おかげ様で、問題解決方法の視野を広げることができました。
ありがとうございました。

お礼日時:2006/03/16 01:44

このQ&Aに関連する人気のQ&A

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

Qバッチファイルで多重起動を防ぐ

とあるプログラムを定期的に
バッチファイルで起動させています。
プログラムは処理が完了すると自動で終了させています。

ただ、時間の間隔はさほど大きくないため、
先だっての起動プログラムが動いているときに
次のタスクにて2重でプログラムが動き出す可能性が出てきました。

バッチファイル上で、その名称のプログラムが動いていないか確認し、
動いていた場合は起動しないようにできないでしょうか?

Aベストアンサー

バッチファイル上でタスクを監視するのは出来ないと思います。

バッチから起動している「とあるプログラム」が何言語で作られているかわかりませんが、そっちで2重起動禁止は実現できませんか?

もしくは、バッチファイルの実行中はAというファイルを作成しておくようにして、「Aと言うファイルがあればプログラムを起動しない」という制御を入れるとか・・・。
※この場合、バッチファイルはプログラムが終了するまでWAITしないと意味ないですけど^^;

QJava 特定プロセス名前取得方法について

Java 特定プロセス名前取得方法について

こんにちわ。
昨日に引続きまた質問させてください。

Javaで特定のプロセス名(OpenOfficeのプロセス名:soffice.exeだったかな?)を取得したいのですが、何か良い方法は無いでしょうか?

環境
eclipse3.5
jdk1.5
jooconverter.jar
openoffice1.4

やりたいこと
・ExcelからPDFにファイル内容を丸ごと変換(jooconverter.jar、openofficeを使用)
・どうやら、openofficeのコネクタを取得しなければ、変換出来ない為Thrad.sleep()で若干とめてます。
・その止めるのを毎回ではなく、1日1回若しくはopenofficeが起動していない時だけにしたいのです。

こんな感じでやりたい
~中略~
// プロセス名取得
String pName = …;

// openofficeが起動しているかのチェック
if (pName.equals("")) {
    // openoffice起動
    ~中略~
// 処理を一旦停止    
    Thread.sleep(60000);
}

// コネクト接続処理
~中略~

// 変換処理
~中略~


補足
何故プロセスIDではないかというと、ネットで調べたら固定ではなく、毎回変動するようなので名前がいいなーと思いました。
もし、変動ではなく固定にすることが出来るなら、IDも可能です。

どなたか分かる方、ご教授頂けましたら幸いです。

Java 特定プロセス名前取得方法について

こんにちわ。
昨日に引続きまた質問させてください。

Javaで特定のプロセス名(OpenOfficeのプロセス名:soffice.exeだったかな?)を取得したいのですが、何か良い方法は無いでしょうか?

環境
eclipse3.5
jdk1.5
jooconverter.jar
openoffice1.4

やりたいこと
・ExcelからPDFにファイル内容を丸ごと変換(jooconverter.jar、openofficeを使用)
・どうやら、openofficeのコネクタを取得しなければ、変換出来ない為Thrad.sleep()で若干とめてます。
・その止めるのを毎回では...続きを読む

Aベストアンサー

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

public class ProcessGetter {
//プロセス表示コマンド(Windows)
//mainで使うために、やむを得ずのstatic
private final static String PS_COMMAND = "tasklist";

//ProcessBuilderにプロセス表示コマンド登録
//mainで使うために、やむを得ずのstatic
private final static ProcessBuilder psbuilder = new ProcessBuilder(PS_COMMAND);

//mainで使うために、やむを得ずのstatic
private final static List<String> list = new ArrayList<String>();

/*
* 実行中のプロセスを返す
*/
public static List<String> getProcess(){

try {
//コマンド実行
Process p = psbuilder.start();

//コマンドのコンソール表示を受け取る
BufferedReader bufreader = new BufferedReader
(new InputStreamReader(p.getInputStream()));
//ArrayListに突っ込みまくる
while (true) {
String tasks = bufreader.readLine();
list.add(tasks);

//コマンドライン表示終了時にストリームをクローズ
int c = p.getInputStream().read();
if (c == -1) {
p.getInputStream().close();
break;
}
}

return list;

} catch (IOException e) {
// TODO 自動生成された catch ブロック
e.printStackTrace();
}finally{
return list;
}
}


public static void main(String[] args) {

List<String> pslist = getProcess();
for(String str : pslist)
{
System.out.println(str);
}
}
}

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

public class ProcessGetter {
//プロセス表示コマンド(Windows)
//mainで使うために、やむを得ずのstatic
private final static String PS_COMMAND = "tasklist";

//ProcessBuilderにプロセス表示コマンド登録
//mainで使うために、やむを得ずのstatic
private final static ProcessBuilder psbuilder = new ProcessBuilder(PS_COMMAND);

//mainで使う...続きを読む

QIOException ってどういうときに起こるのでしょうか?

IOException ってどういうときに起こるのでしょうか?

http://www.atmarkit.co.jp/fjava/rensai2/javaent12/javaent12.html
を見て勉強しています。

  catch ( IOException e) {
    System.out.println( "キーボードが故障しているのかもしれません" );
  }

と書いてあります。
ハード(キーボード)が故障しているのを Java のプログラムのレベル(ソフトウェア)で感知できるというのがよくわかりません。「

NumberFormatException の方はわかるのですが・・・

Aベストアンサー

現実的には、キーボードからの入力でIOExceptionが発生することは、
ほとんどあり得ないと思います。
そもそも、キーボードが故障していたとしても、
IOExceptionは投げられないでしょう。
「キーボードが故障しているのかもしれません」というのは、
その記事の著者が冗談で書いたのだと思います。

ではなぜ、try-catchを書かなくてはいけないのか?
InputStreamやBufferedReaderは、
データ入力を抽象化したものだからです。
実際の入力元はキーボードだったり、ファイルだったり、
ネットワーク接続だったりするわけですけど、
InputStreamは、その入力元の情報を持っていないので、
データを読み取る際は常に
IOExceptionをキャッチするコードを書かなくてはいけません。
たとえ、絶対にIOエラーが発生しないストリームだとしても。

さらに付け加えるなら、
そもそも「標準入力=キーボード」であるとは限りません。
(一般的にはキーボードであることが多いですが。)
Javaでは、
System.setIn(InputStream)
を呼び出して、標準入力を変えてしまうことができますし、
標準入力を指定してプログラムを実行することができるOSもあります。

追伸1:
例外をキャッチしたときは、
スタックトレースをプリントすることをおすすめします。
catch (IOException e) {
e.printStackTrace();
}

追伸2:
そのプログラムでIOExceptionを発生させる最も簡単な方法は、
readLine()を呼び出す前に
標準入力(System.in)を閉じてしまうことです。
System.in.close();

現実的には、キーボードからの入力でIOExceptionが発生することは、
ほとんどあり得ないと思います。
そもそも、キーボードが故障していたとしても、
IOExceptionは投げられないでしょう。
「キーボードが故障しているのかもしれません」というのは、
その記事の著者が冗談で書いたのだと思います。

ではなぜ、try-catchを書かなくてはいけないのか?
InputStreamやBufferedReaderは、
データ入力を抽象化したものだからです。
実際の入力元はキーボードだったり、ファイルだったり、
ネットワーク接...続きを読む

QSystem.exit()の値を取得したい

 今日は、JAVA初心者です、宜しくお願いします。

 プログラムの終了時の結果を System.exit()で取得したいのですが、どのようなメソッドが
あるのでしょうか。

 宜しくお願いします。

Aベストアンサー

System.exit()で何かを取得することはできません。
「System.exit()の値を取得したい」だったら、Windowsではこんな感じ。引数の数をそのままプログラムの終了コードにしています。

public class SysExit {
public static void main(String[] args) {
System.exit(args.length);
}
}

>java SysExit
>echo %ERRORLEVEL%
0

>java SysExit 1 2 3
>echo %ERRORLEVEL%
3

Qプログラムの二重起動防止

プログラムの二重起動を防止したいんですが、V.B.のようにjavaにも、二重防止の関数があるのでしょうか?
あるとすれば、どういったものなのでしょうか?

Aベストアンサー

Javaアプリケーションの事でいいんですよね?
二重起動防止クラスは Singletonパターンを使えば出来るんじゃないですか?
その応用で出来るかと思いますが。。。

QSwingでJtableのヘッダ行が表示されません

SwingでJtableのヘッダ行が表示されません

解決方法とどうして表示されなかったのか理由もできればお願いします。
import java.util.Vector;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableModel;

public class Table_Calendar extends JFrame{
Vector<String>[] data = new Vector[3];
public static void main(String args[]){
new Table_Calendar();
}
public Table_Calendar(){
super();
// ウィンドウサイズ
this.setSize(800, 600);
// レイアウト
this.setLayout(null);
// ウィンドウクローズ時の処理
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// セルのデータ作成
for (int i = 0; i < 3; i++) {
data[i] = new Vector<String>();
}
// data[0]に名前、data[1]に住所、data[2]に電話番号
data[0].addElement("鈴木一郎");
data[1].addElement("東京都");
data[2].addElement("xxxxxxxxxx");
// テーブル作成
TableModel tableModel = new AbstractTableModel() {
// 行数
public int getRowCount() {
return 1;
}

// 列数
public int getColumnCount() {
return 3;
}

// row行column列の値をセット
public Object getValueAt(int row, int column) {
return data[column].elementAt(row);
}

// タイトル部の値をセット
public String getColumnName(int column) {
switch (column) {
case 0:
return "名前";
case 1:
return "住所";
case 2:
return "電話番号";
}
return "";
}
};
JTable table = new JTable(tableModel);
table.setLocation(10, 20);
table.setSize(600,500);
JPanel panel2 = new JPanel();
panel2.setLayout(null);
panel2.add(table);
/*setBounds(int x,int y,int width,int height)*/
panel2.setBounds(10, 10, 700,700);
this.add(panel2);
this.setVisible(true);
}

}

SwingでJtableのヘッダ行が表示されません

解決方法とどうして表示されなかったのか理由もできればお願いします。
import java.util.Vector;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableModel;

public class Table_Calendar extends JFrame{
Vector<String>[] data = new Vector[3];
public static void main(String args[]){
new Table_Calendar();
}
public Table_Calendar(){
super()...続きを読む

Aベストアンサー

No.1様の回答のとおり、JScrollPaneに入れると自動で表示されるようです。

GUI系は正直全然知らないのですが、APIには
>スタンドアロンのビュー (JScrollPane の外側) 内で JTable を使用し、ヘッダーを表示する場合は、getTableHeader() を使用してヘッダーを取得し、個別に表示できます。
とあります。
JscrollPaneの外側でヘッダーを表示するサンプルが、チュートリアルにありました。
http://download.oracle.com/javase/tutorial/uiswing/components/table.html#show
>container.setLayout(new BorderLayout());
>container.add(table.getTableHeader(), BorderLayout.PAGE_START);
>container.add(table, BorderLayout.CENTER);
とすると表示できるようです。

まずはAPIなどを見てみるようにしてみてはいかがでしょうか。

No.1様の回答のとおり、JScrollPaneに入れると自動で表示されるようです。

GUI系は正直全然知らないのですが、APIには
>スタンドアロンのビュー (JScrollPane の外側) 内で JTable を使用し、ヘッダーを表示する場合は、getTableHeader() を使用してヘッダーを取得し、個別に表示できます。
とあります。
JscrollPaneの外側でヘッダーを表示するサンプルが、チュートリアルにありました。
http://download.oracle.com/javase/tutorial/uiswing/components/table.html#show
>container.setLayout(new BorderLayout...続きを読む

QJDialogの×(閉じる)ボタン

JDialogの右上に付いている×(閉じる)ボタンを
使用可能にしたり、使用不可能にしたいのですが、
setEnabled(false)やsetClosable(false)みたいな、
コマンドは無いのでしょうか?

または、×(閉じる)ボタンを出さない方法でも
よいので教えてください。

宜しくお願いします。

Aベストアンサー

javax.swing.JDialog#setDefaultCloseOperation()
を使います。

引数はjavax.swing.WindowConstantsの。。。

・HIDE_ON_CLOSE
・DISPOSE_ON_CLOSE
・DO_NOTHING_ON_CLOSE

のいずれかの定数を用います。
動作の違いはWindowConstantsのAPIをご覧下さい。

Q(Swing)JTextFieldを半角のみ入力可能にする方法

JTextField で半角のみ入力可能なチェックを行いたいのですがどうもうまくいきません。
下記のソースは、入力桁数制限チェックと、全角チェックを行っているのですが
半角を入力した後に全角を入力すると、JTextFieldの値が消えてしまいます。
どなたがご指導よろしくお願いします。
もしくは、下記ソースの他によいチェック方法等ありましたら、教えてくださいm(__)m
よろしくお願いいたします。

=======================================
userText.setDocument( new LimitedDocument( 8) );

/**
* 指定文字数・全角チェック
*/
private class LimitedDocument extends PlainDocument {
int limit;
LimitedDocument( int limit ){ this.limit = limit; }

public void insertString( int offset, String str, AttributeSet a ) {
try{

String wholeText = getText( 0, getLength() );
// 文字数チェック
byte[] b = wholeText.getBytes();
if( b.length >= limit ){
return;
}
char c = str.charAt(0);
// 文字が半角だったら挿入する。
if (c < 256 || (c >= 0xff61 && c <= 0xff9f)) {
super.insertString(offset, String.valueOf(c), a);
}
else {
}
}
catch( BadLocationException e ) {
System.out.println( e );
}
}
}

=======================================

JTextField で半角のみ入力可能なチェックを行いたいのですがどうもうまくいきません。
下記のソースは、入力桁数制限チェックと、全角チェックを行っているのですが
半角を入力した後に全角を入力すると、JTextFieldの値が消えてしまいます。
どなたがご指導よろしくお願いします。
もしくは、下記ソースの他によいチェック方法等ありましたら、教えてくださいm(__)m
よろしくお願いいたします。

=======================================
userText.setDocument( new LimitedDocument( 8) );

/**
*...続きを読む

Aベストアンサー

こんばんわ。こんなのはどうでしょう?

public void insertString(int offs, String str, AttributeSet a)
throws BadLocationException {
if (str == null || str.length() == 0)
return;

String strNew = new String();

// 挿入文字数分ループ
char[] strings = str.toCharArray();
for (int i = 0; i < strings.length; i++) {
char ch = strings[i];

// 禁則文字なら挿入しない
if (!isJapanese(ch)) {
ch = changeCharacter(ch);
strNew += String.valueOf(ch);
} else {
continue;
}
}
super.insertString(offs, strNew, a);
}

public static boolean isJapanese(char ch) {
if (((ch < 20) || (ch > 127))
&& ch != '\\'
&& ch != '\t'
&& ch != '\n'
&& ch != '\r'
&& ch != '\f') {
return true;
}
return false;
}

こんばんわ。こんなのはどうでしょう?

public void insertString(int offs, String str, AttributeSet a)
throws BadLocationException {
if (str == null || str.length() == 0)
return;

String strNew = new String();

// 挿入文字数分ループ
char[] strings = str.toCharArray();
for (int i = 0; i < strings.length; i++) {
char ch = strings[i];

// 禁則文字なら挿入しない
if (!isJapanese(ch)) {
ch = changeCharacter(ch);
strNew += String.valueOf(ch);
} else {
continue;
...続きを読む

Qmain()を持つクラスが2つ以上あるexecutable jar

main()を持つクラスが2つ以上あるexecutable jar
を作成して、
main()を持つクラスを
必要に応じて、起動仕分けることは
可能なのでしょうか?

もし、可能であるとすれば
マニフェストファイルには
どのように記述すればよいのでしょうか?

そして、
java -jar
コマンドで起動するときにどのようにすればよいのでしょうか?


不可能であれば不可能であるということを
教えてください。

以上

Aベストアンサー

マニフェストファイルを用意しなくても、クラス名を直接指定する通常のコマンド形式
java -classpath <jarファイル名> <mainがあるクラス名> <コマンドライン引数>
で <mainがあるクラス名> を変えれば起動仕分けることは可能です。

マニフェストファイルには Main-Class 属性を一つしか定義できないので、クラス名を指定しない
java -jar <jarファイル名> <コマンドライン引数>
の形式で起動仕分けることは出来ないと思います。

QTmocatのバージョン

Tomcatのバージョンの確認方法を教えてください。
http://ローカルホスト:8080では表示できなかったので
その他の方法で。(8080は使えないようにしています)
RELEASE NOTEに沢山書いてあるバージョンのうち、一番新しいバージョンがそのTomcatのバージョンになるのかな?
と思いつつも、もっと分かり易い方法を探しています。

Aベストアンサー

こんにちわ。
あまり自信がないんですが、

以前私が確認した方法を記載いたします。

TOMCATが立ち上がっている状態で、
頁が存在しないアドレスを打ち込む。

http://localhost/aaaaaa等。

そうすると、おそらく404エラーになるので、
そのエラーページの下部にTomcatのバージョンが記載されているはずです。

もっといい確認方法があるかもしれませんが。。


このQ&Aを見た人がよく見るQ&A

人気Q&Aランキング