Javaのコマンドラインプログラムをログオフ中も実行する

Windows2008環境でJavaコマンドラインプログラムをログオフ中も実行するには、タスクスケジューラに起動用のバッチファイルを登録した上で、「ユーザーがログオンしているかどうかにかかわらず実行する」を選択しておく必要があります。



あるお仕事で、「java クラス名」でコマンドラインから起動するようなJavaプログラムを常時起動したいのですが、ログオフするとプロセスが終了してしまうとう問題に突き当たりました。
これは、Windowsだとユーザーのログオフ処理をする際に、対象ユーザーが起動しているプログラムをすべて終了してしまう事に起因しています。こういう要件は環境がUNIX系ならそう難しい話でもないのですが、環境がWindows 2008 R2なのでUNIXで使えるような手段は使えず。

@IT:Javaアプリケーションをログオフ中も実行させ続けるには には

これをコンパイルし、「java Count」として実行すると、「count.txt」が作成され、
1秒ごとに経過時間が書き込まれる。コマンド・プロンプトで「Ctrl+C」を押すか、ログオフするとプログラムは終了する。
では、これをログオフ中も実行させるために、タスクとして登録してみよう。
こうすると、ログオン/ログオフとは関係なく、実行されるようになる。

とあり、「javaw -Xrs」で起動すれば良いみたい。Javaマニュアルを見ると、J2SE 1.3.1以降は「-Xrs」という拡張オプションを受け付けており、こいつがあると

Sun の JVM で -Xrs オプションを使用すると、JVM は、コンソール制御ハンドラをインストールしません。この場合、JVM は、CTRL_C_EVENT、CTRL_CLOSE_EVENT、CTRL_LOGOFF_EVENT、および CTRL_SHUTDOWN_EVENT の監視と処理を行いません。

だそうです。Javaの7でも英語のマニュアル読む限り、特に仕様は変わってない様子。



サンプルコードを使ってさっそくテスト。

  • コマンドラインから「javaw -Xrs Count」で起動 → ログオフ時に終了されてしまう
  • 管理者権限コマンドラインから「javaw -Xrs Count」で起動 → ログオフ時に終了されてしまう
  • タスクスケジューラに「javaw -Xrs Count」を登録 → そもそも起動しない
  • タスクスケジューラに起動用のバッチファイルを登録 → ログオフ時に終了されてしまう
  • タスクスケジューラに起動用のバッチファイルを登録した上で、「ユーザーがログオンしているかどうかにかかわらず実行する」を選択 → 成功

バッチファイルは以下のような体裁で起動してます。

CD 対象プログラムのディレクト
start /b cmd /c javaw -Xrs Count

あえて「start /b cmd」をつけてるのは、これじゃないと私の環境ではうまく行かなかったから。他にやり方あるのかもしれませんが(;´∀`)

タスクスケジューラから起動したプログラムは、自分自身のユーザー権限で動いていたとしても、タスクマネージャから「全てのユーザのプロセスを表示する」にしないと見えないのに気付かず、ちょいとハマりましたが、こんな結果でした。

Windows起動時に自動実行するようなプログラムは「LOCAL SERVICE」などの特殊なアカウントに紐づける必要があるかと思っていたのですが、特殊アカウント是非や管理者権限有無では変わらない様子。(元々のプログラムが管理者権限を必要とするようなプログラムならどうかわかりませんが)

注意点として、マニュアルには

  • Ctrl + Break キーによるスレッドダンプを利用できない
  • シャットダウンフック処理の実行は、JVM が終了しようとしている時点で System.exit() を呼び出すなどして、ユーザコード側で行う必要がある

とあるので、どんなプログラムでも行けるわけではないので、そのへんは各自が確認しないといけませんね。