1
public class MainClass { 

private static final int size = 5; 

private ExecutorService prodExec = Executors.newFixedThreadPool(size); 
private ExecutorService consExec = Executors.newFixedThreadPool(size); 

//main method here 

public void start(String[] args) { 

    for (int index = 0; index < size; index++) { 
     Runnable producer = new Producer(consExec, listOfIds); 
     prodExec.execute(producer); 
    } 

    Runtime.getRuntime().addShutdownHook(new Thread() { 
     public void run() { 
      prodExec.shutdown(); 
      try { 
       prodExec.awaitTermination(10, TimeUnit.SECONDS); 
      } catch (InterruptedException ignore) { 
      } 

      consExec.shutdown(); 
      try { 
       consExec.awaitTermination(10, TimeUnit.SECONDS); 
      } catch (InterruptedException ignore) { 
      } 
     } 
    }); 
    } 
} 
public class Producer implements Runnable { 

private ExecutorService consExec; 
private List<Long> list; 

public Producer(ExecutorService exec, List<Long> list) { 
    this.consExec = exec; 
    this.list = list; 
} 

public void run() { 
    for (Long id: list) { 
     data = get data from db for the id 
     consExec.execute(new Consumer(data)); 
    } 
} 
} 
public class Consumer implements Runnable { 

public void run() { 
    // call web service 
} 
} 

ユーザーがシャットダウンを要求したときに、Ctrl + Cキーを押してシナリオを処理したいと考えています。私はこれがシャットダウンフックで実行できると思います。しかし、上記のコードのように、各プロデューサは、処理するIDのリスト(250かもしれません)を取得します。つまり、dbを呼び出してIDのデータを取得し、データをコンシューマスレッドに送信します。サービス。プロデューサーのコンシューマーリクエストの取り消し

プロデューサスレッドのそれぞれのforループから、シャットダウンが要求されたときに各スレッドがまだプロセスされていないIDを処理しないようにするにはどうすればよいですか? shutDownHookを動作させることができましたが、シャットダウン要求の場合にrun()メソッドを終了するためにrunメソッド内のロジックを各スレッドに組み込む方法を確認できませんでした。ブール変数(AtomicBoolean)を外部的に設定すると、各スレッドがすべてのIDを処理する前にforループをチェックインすることがありますか?

私が理解しているように、shutdown()を呼び出すと、送信されたすべてのタスクが実行されて終了します。この場合、タスクはすでにexecutorサービス上でキューに入れられているため、処理を停止する方法はありません。

shutdown()の代わりにshutdownNow()を呼び出すと、予期しない結果が生じることがありますか?

答えて

1

shutdownNowとshutdownは、現在実行中のタスクを最初に完了させるかどうかによって異なります。

すぐに停止したい場合は、2つのことを行います。最初にshutdownNowを呼び出します。 2つは、runメソッド内でスレッドの中断ステータスをテストします。

public class Producer implements Runnable { 

private ExecutorService consExec; 
private List<Long> list; 

public Producer(ExecutorService exec, List<Long> list) { 
    this.consExec = exec; 
    this.list = list; 
} 

    public void run() { 
     for (Long id: list) { 
      if(Thread.currentThread().isInterrupted()){ 
       //the shutdownNow method has been called (or may a future.cancel(true)) 
      } 
      data = get data from db for the id 
      consExec.execute(new Consumer(data)); 
     } 
    } 
} 

ここで、runメソッドが現在のスレッドが中断されていることがわかります。その実行方法でデータをクリーンアップして終了できます

+0

ifブロックにsysout( "中断")ステートメントを追加しようとしましたが、提案したようにshutdownNow()を実行しようとしましたが、スレッドによってはステートメントが印刷されませんでした。たとえば、1000個のスレッドを生成し、それぞれに一意の名前を割り当て、shutDownHook()でshutdownNow()を呼び出し、Ctrl + Cを押しました。中断されたステートメントは、いくつかのスレッド、すなわちrun()を終了したスレッドの総数と中断されたスレッドの数が、実行されたスレッドの総数に加算されません。私は、interruptNow()のスレッドでinterrupt()が呼び出されると確信できますか? – Oxford

+0

これはおそらく、あなたが作成した1000スレッドのうちのほんの数だけが実際に何らかの作業をしていたためです。あれは正しいですか?その場合、残りの部分はBlockingQueueを待っています。この時点での中断は、ExecutorServiceによって処理されます。簡単な答えは、他のM個のスレッド(実際に実行されている1000〜N個のタスクであるM個のスレッド)が 'public void run()'メソッドになかったからです。 –

+0

そして、ExecutorServiceによって処理されると、 ExecutorServiceは残りのスレッドを適切にシャットダウンします。 –

1

Java SE 6+を使用している場合は、JMXクラスにアクセスできます。私たちが実行しているサービスを "シャットダウン"するためにこれを使うと便利です。

本質的には、サービスをJMXサービスとして登録します。そして、それを消すためにドライバークラスを使用してください。

実際のサービスクラスでは、本質的に無限ループを使用して条件が真であるかどうかを確認するロジックを実装します(これはデフォルトです)。

JMXサービスに接続する別のドライバクラスを作成し、ループ条件の値をfalseに変更します。その後、ループ状態になると(正常に)シャットダウンされ、次の値のセットは処理されません。

関連する問題