1

次のコードがあります。

public static void main(String[] args) {

    // login event
    String event = "login";
    System.out.printf("Handling event: %s %s\n",event,getCurrentLogin());
    sendMessage(event, getCurrentLogin());

    // logout or shutdown event
    Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
        @Override
        public void run() {
                String event = "logout";
                System.out.printf("Handling event: %s %s\n",event,getCurrentLogin());
                sendMessage(event, getCurrentLogin());
        }
    }));
 }

ユーザーのログインとログアウトを記録するための非常に単純なプログラムです。問題は、関数 main() の最後に到達するとプログラムが終了することです。

シャットダウン イベント フックを正しく使用していますか? 複雑な Windows サービスを作成したくありません。リモート接続された Windows セッションに使用されるため、非常に単純なアプリケーションでなければなりません。

ログインの終了を待つバックグラウンドについて何か提案はありますか?

4

6 に答える 6

2

ShutdownHook は、JVM が終了し、「sendMessage」を実行した後、プログラムが何もしていないときに実行されるスレッドです。

sendMessage(event, getCurrentLogin());

コンソールの Ctrl+C のように、シグナルが終了するまで待つ必要があります。ロックまたはセマフォがプログラムのファイナライズを回避するのを待つだけで、終了する必要があるときにそのロックを解放する必要があります。

于 2012-01-17T16:02:51.703 に答える
1

サンプルを機能させるために、サンプルにラッチを追加しました。残念ながら、テストする IDE がありませんが、アイデアを得るにはこれで十分です。

編集: 以下の例では、ログインとログアウトの両方が出力されます。

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

    public class Test {
        public static void main(String[] args) throws Exception {

            // login event
            String event = "login";
            System.out.printf("Handling event: %s %s\n", event, getCurrentLogin());
            sendMessage(event, getCurrentLogin());
            final CountDownLatch latch = new CountDownLatch(1);

            // logout or shutdown event
            Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
                @Override
                public void run() {
                    String event = "logout";
                    System.out.printf("Handling event: %s %s\n", event, getCurrentLogin());
                    sendMessage(event, getCurrentLogin());
                    latch.countDown();
                }
            }));
            latch.await(2, TimeUnit.SECONDS);
        }

        private static void sendMessage(String event, Object currentLogin) {
        }

        private static Object getCurrentLogin() {
            return "X";
        }
    }
于 2012-01-17T16:13:21.020 に答える
0

ここにはいくつかの良い答えがありますが、まだ不足している情報がいくつかあります。

コードがシャットダウン フックを登録するmainと、main が最後に到達して戻ります。シャットダウン フックは、最後の非デーモン スレッドが終了したときに呼び出されます。main が唯一の非デーモン スレッドであると思われるため、main終了するとすぐにフックが呼び出されます。

プログラムをすぐに終了させたくない場合mainは、ループして何らかのシグナルを待つ必要があります。sendMessageあなたの質問の文脈から、私はそれが呼び出しからの何らかの応答を聞いているべきだと思いますか? control-c を待ちたい場合は、これに対する @JB Nizet の回答が気に入っています。

public static void main(String[] args) throws InterruptedException {
    ...
    Runtime.getRuntime().addShutdownHook(...);
    // wait until control-c is called
    final Object o = new Object();
    synchronized(o) {
        while(true) {
            o.wait();
        }
    }
}

シャットダウン フックを登録した後に待機を開始して、シャットダウン コードが実行されるようにします。

于 2012-01-17T22:33:52.023 に答える
0

私の理解が正しければ、OS がプログラムを停止するまで無限に待機したいということでよろしいですか? その場合、少なくとも 1 つのデーモン スレッドを実行する必要があります。

public static void main(String[] args) throws InterruptedException {
    //...
    final Object o = new Object();
    synchronized(o) {
        while(true) {
            o.wait();
        }
    }
}

ただし、OSがJVMを十分に穏やかに強制終了し、シャットダウンフックが実行されるかどうかはわかりません。試して。

于 2012-01-17T16:04:11.973 に答える
0

アプリケーションがファイナライズされると、シャットダウン フックが呼び出されます。したがって、アプリケーションを永久に実行させたい場合は、次のように実装する必要があります。

while (true) {
    //Your logic here
}

デーモンまたはスケジューラーを作成したい場合は、Quartz http://quartz-scheduler.orgなどのフレームワークを使用する必要があるかもしれません。

デーモンを実装したい場合は、 http: //yajsw.sourceforge.nethttp://wrapper.tanukisoftware.com/のようなサービス ラッパーを使用できます。

于 2012-01-17T16:04:27.910 に答える
-1

CountDownLatcha を使用してメインスレッドを待機させておく1 つの方法を次に示します。

public static void main(String[] args) {

    // login event
    String event = "login";
    System.out.printf("Handling event: %s %s\n",event,getCurrentLogin());
    sendMessage(event, getCurrentLogin());

    final CountDownLatch latch = new CountDownLatch(1);

    // logout or shutdown event
    Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
        @Override
        public void run() {
                String event = "logout";
                System.out.printf("Handling event: %s %s\n",event,getCurrentLogin());
                sendMessage(event, getCurrentLogin());
                latch.countDown();
        }
    }));

    latch.await();
 }
于 2012-01-17T16:10:21.440 に答える