14

あるフィールドの値の変化についてデータベースを継続的にポーリングするプログラムがあります。これはバックグラウンドで実行され、現在、while(true)メソッドとsleep()メソッドを使用して間隔を設定します。これは良い習慣かどうか疑問に思いますか?そして、これを実装するためのより効率的な方法は何でしょうか?プログラムは常に実行することを目的としています。

したがって、プログラムを停止する唯一の方法は、プロセスIDに対してkillを発行することです。プログラムは、JDBC呼び出しの途中である可能性があります。どうすればもっと優雅にそれを終わらせることができますか?スレッドによって定期的にチェックされるフラグを使用して、ある種の出口戦略を考案することが最善の選択肢であることを理解しています。しかし、このフラグの値を変更する方法/条件を考えることはできません。何か案は?

4

13 に答える 13

12

これは良い習慣かどうか疑問に思いますか?

いいえ、良くありません。時々、それはあなたが持っているすべてです、しかしそれは良くありません。

そして、これを実装するためのより効率的な方法は何でしょうか?

そもそも、どのようにしてデータベースに入るのですか?

最善の変更は、データベースを挿入/更新するプログラムを修正して、データベースとプログラムに送信する要求を行うことです。JMSトピックは、この種のことに適しています。

次善の変更は、データベースにトリガーを追加して、各挿入/更新イベントをキューにエンキューすることです。キューは、プログラムで処理するためにJMSトピック(またはキュー)にフィードすることができます。

フォールバックプランは、ポーリングループです。

ただし、ポーリングループは簡単に機能しないはずです。他のJDBCプロセスが機能するように、メッセージをキューにドロップする必要があります。終了要求は、JMSキューにドロップできるもう1つのメッセージです。プログラムが終了メッセージを受け取ったら、それは絶対に前のJDBC要求で終了する必要があり、正常に停止できます。

これを行う前に、ESBソリューションを確認してください。SunのJCAPSまたはTIBCOにはすでにこれがあります。MulesourceJitterbitなどのオープンソースESBには、この機能がすでに構築およびテストされている場合があります。

于 2008-12-23T22:37:59.640 に答える
8

これは本当に大きな問題であり、この形式で完全に答えることはできません。自分に有利に働き、JavaConcurrencyinPracticeを購入してください。そこにあるJava5+プラットフォームでの並行性のためのより良いリソースはありません。この主題に専念する章全体があります。

JDBC呼び出し中にプロセスを強制終了するという点では、それで問題ありません。JDBC呼び出しの中断には問題があると思いますが(できないという点で)、それは別の問題です。

于 2008-12-23T22:30:32.013 に答える
6

他の人が言ったように、ポーリングしなければならないという事実は、おそらくシステムの設計に深刻な問題があることを示しています...

プロセスをもう少し適切に「強制終了」したい場合は、Ctrl+を押したときに呼び出されるシャットダウン フックをインストールできCます。

volatile boolean stop = false;

Runtime.getRuntime().addShutdownHook(new Thread("shutdown thread") {

    public void run() {

        stop = true;
    }
});

その後、停止変数を定期的にチェックします。

より洗練された解決策は、イベントを待機することです。

boolean stop = false;

final Object event = new Object();

Runtime.getRuntime().addShutdownHook(new Thread("shutdown thread") {

    public void run() {

        synchronized(event) {

            stop = true;
            event.notifyAll();
        }
    }
});

// ... and in your polling loop ...
synchronized(event) {

    while(!stop) {

        // ... do JDBC access ...
        try {

            // Wait 30 seconds, but break out as soon as the event is fired.
            event.wait(30000);
        }

        catch(InterruptedException e) {

            // Log a message and exit. Never ignore interrupted exception.
            break;
        }
    }
}

またはそのようなもの。

于 2008-12-24T04:14:18.013 に答える
3

タイマー(または同様のもの)は、少なくともそれを再利用して、スリープ、スケジューリング、例外処理などのすべての詳細を処理できるという点で優れていることに注意してください...

アプリが停止する理由はたくさんあります。1つだけに焦点を当てないでください。

JDBC作業で物事が半分正しい状態のままになることが理論的にも可能である場合は、修正する必要のあるバグがあります。すべてのDB作業はトランザクション内にある必要があります。行くべきか行かないか。

于 2008-12-23T22:57:30.537 に答える
3

これはJavaです。処理を2番目のスレッドに移動します。今、あなたはすることができます

  • ループでstdinから読み取ります。誰かが「QUIT」と入力した場合は、whileフラグをfalseに設定して終了します。
  • STOPボタンを使用してAWTまたはSwingフレームを作成します。
  • Unixデーモンのふりをして、サーバーソケットを作成します。誰かがソケットを開いて「QUIT」を送信するのを待ちます。(これには、スリープをタイムアウト付きの選択に変更できるという追加のボーナスがあります。)

これには何百ものバリアントが必要です。

于 2008-12-23T23:12:00.743 に答える
2

ループを次回終了するように指示するフラグを設定するSIGTERMのシグナルハンドラーを設定します。

于 2008-12-23T22:30:55.460 に答える
1

「プログラムはJDBC呼び出しの途中にある可能性があります。どうすれば、より適切にプログラムを終了できますか?」という質問について。-実行中のjdbcトランザクションを中止するにはどうすればよいですか?を参照してください。

sleep()でポーリングを使用することが正しい解決策になることはめったにないことに注意してください-不適切に実装すると、CPUリソースを占有してしまう可能性があります(JVMスレッドスケジューラは、スレッドのスリープとウェイクアップに膨大な時間を費やすことになります)。

于 2008-12-23T22:59:23.547 に答える
0

それがあなたのアプリケーションであり、それを変更できる場合は、次のことができます。

  • ファイルを読み込ませる
  • フラグの値を読み取ります。
  • 強制終了したい場合は、ファイルを変更するだけで、アプリケーションは正常に終了します。

そこまで頑張る必要はありません。

于 2008-12-23T22:40:32.630 に答える
0

Java に実装されている割り込みメカニズムについて誰も言及していないことに驚いています。スレッドを停止する問題の解決策になるはずです。他のすべてのソリューションには少なくとも 1 つの欠陥があります。そのため、このメカニズムを Java 同時実行ライブラリに実装する必要があります。

スレッドに interrupt() メッセージを送信することでスレッドを停止できますが、スレッドが中断される方法は他にもあります。これが発生すると、InterruptedException がスローされます。そのため、たとえば sleep() を呼び出すときにそれを処理する必要があります。ここで、データベース接続を閉じるように、クリーンアップを実行して正常に終了できます。

于 2009-04-09T11:19:13.373 に答える
0

フィールドを、(概念的に) プロセス ID とタイムスタンプを含む複合値にすることができます。[できれば、2 つ以上のフィールドを使用してください。] フィールドへのアクセスを所有するプロセスでスレッドを開始し、スレッドをループさせて、スリープ状態にし、タイムスタンプを更新します。次に、フィールドへのアクセスを所有するのを待っているポーリング プロセスは、タイムスタンプが時間 T (更新ループのスリープ間隔の時間よりもはるかに長い時間) 内に更新されていないことを確認し、以前に所有していたプロセスが終了したと見なすことができます。 .

しかし、これはまだ失敗する傾向があります。

他の言語では、常に flock() 呼び出しを使用してファイルを同期しようとします。Javaの同等物が何であるかわかりません。可能であれば、実際の同時実行を取得してください。

于 2008-12-24T05:00:46.763 に答える
0

次のような問題のために、現在の会社のユーティリティ ライブラリに Service クラスを作成しました。

public class Service implements Runnable {

    private boolean shouldStop = false;

    public synchronized stop() {
        shouldStop = true;
        notify();
    }

    private synchronized shouldStop() {
        return shouldStop;
    }

    public void run() {
        setUp();
        while (!shouldStop()) {
            doStuff();
            sleep(60 * 1000);
        }
    }

    private synchronized sleep(long delay) {
        try {
            wait(delay);
        } catch (InterruptedException ie1) {
            /* ignore. */
        }
    }

}

もちろん、これは完全にはほど遠いですが、要点を理解する必要があります。stop()これにより、プログラムを停止したいときにメソッドを呼び出すだけで、正常に終了します。

于 2008-12-23T23:47:38.690 に答える