2016-09-07 7 views
0

Executor Servicesで最大待機時間を設定する方法はありますか。ExecutorServiceのキュー内の最大待機時間

たとえば、真の実行可能時間がSingleThreadExecutorに2つを渡すと、最初のものは永遠に動作し、2番目のものはただ待っています。

2番目のRunnableについてTimeOutExceptionが発生すると予想しています。

public static void main(String[] args) throws IOException { 
     ExecutorService executor = Executors.newSingleThreadExecutor(); 
     for (int i = 0; i < 2; i++) { 
      int finalI = i; 
      executor.execute(new Runnable() { 
       @Override 
       public void run() { 
        while (true) { 
         try { 
          System.out.println("#"+ finalI + " Runnable !"); 
          Thread.sleep(1000); 
         } catch (Exception e) { 
          e.printStackTrace(); 
         } 
        } 
       } 
      }); 
     } 
    } 
+0

実行可能タスクが完了しないようですか?したがって、このスレッドは実行、印刷、スリープ、実行、印刷、スリープ広告の無限大となります。なぜ、このサービスによって別のスレッドが実行されるのでしょうか? –

答えて

1

Executor Servicesに最大待機時間を設定する方法はありますか。

あなたが仕事が始まるのを待っていると話しているのなら、残念なことに答えは「簡単ではない」です。 ThreadPoolExecutorのキューを使用してそれを行うにはいくつかの方法がありますが、それらはハックとみなされ、推奨されません。 ThreadPoolExecutorも拡張できますが、それは複雑になる可能性があります。

1つの[より良い]ソリューションは、キューを外部から管理することです。

// synchronous queue waits for someone to take() from the queue before returning 
final BlockingQueue<Runnable> jobQueue = new SynchronousQueue<Runnable>(); 
... 
// submit all of your threads who get jobs from your queue to run 
executor.execute(new Runnable() { 
    @Override 
    public void run() { 
     while (!Thread.currentThread.isInterrupted()) { 
       try { 
        Runnable job = jobQueue.take(); 
        job.run(); 
       } catch (InterruptedException ie) { 
        // always recommended 
        Thread.currentThread().interrupt(); 
        return; 
       } 
     } 
    } 
}); 
... 
// now we can try to add a job into the queue but if it is full, offer may timeout 
if (!queue.offer(new Runnable() { ... }, 2000, TimeUnit.SECONDS)) { 
    // timed out 
} 

これが役立ちます。

+0

うーん、素敵なトリック! – Mojtabye

1

実行者にはスレッドが1つしかありません。それは内部的に異なるRunnableタスクをキューに入れ、それらを1つずつ完了させようとします。最初のタスクが完了しない場合(真のループのため)、2番目のタスクは決して開始されません。

executeの代わりにsubmitを使用してFutureオブジェクトを取得し、代わりにget操作でタイムアウトを実行することができます。あなたのタスクはタイムアウトされ、あなたはしかしfuture.get(1).cancel(false)

を使用して、それをキャンセルすることができ決まったら

public static void main(String[] args) throws IOException { 
    ExecutorService executor = Executors.newSingleThreadExecutor(); 
    List<Future> future = new ArrayList<>(); 
    for (int i = 0; i < 2; i++) { 
     int finalI = i; 
     future.add(executor.submit(new Runnable() { 
      @Override 
      public void run() { 
       while (true) { 
        try { 
         System.out.println("#"+ finalI + " Runnable !"); 
         Thread.sleep(1000); 
        } catch (Exception e) { 
         e.printStackTrace(); 
        } 
       } 
      } 
     })); 
    } 
    // Check if second task finishes in the next 2 seconds, and throw a TimeoutException if it does not 

    try { 
     future.get(1).get(2000, TimeUnit.MILLISECONDS); 
    } catch (TimeoutException e) { 
     e.printStackTrace(); 
    } 
} 

、すべてのスレッドがあなたのために忙しく働くときにタスクを拒否する場合は、このアプローチを試みることができる:

 BlockingQueue<Runnable> queue = new SynchronousQueue<>(); 
     ExecutorService executorService = new ThreadPoolExecutor(2, 2, 
       0L, TimeUnit.MILLISECONDS, 
       queue); 

このExecutorServiceは、すべてのスレッドがビジー状態の場合、タスクを自動的に拒否します。

+0

私もそれを知っています;)、しかし、TimeOutExceptionを取得するのはどうですか? – Mojtabye

+0

タイムアウトはありません。しかし、 'execute'の代わりに' submit'を使って未来を受け取ることができます。その後、 'future.get(1000、TimeUnit.MILLSECONDS)'を実行すると、タスクの実行が間に合わなくなった場合にTimeoutExceptionがスローされます。私はこの動作を実装するいくつかのコードを表示するために自分の答えを拡張することができます:) –

+0

私に役立つサンプルコードを表示する場合は、私はあなたに感謝します – Mojtabye

関連する問題