2012-04-26 8 views
3

制限付きのバックグラウンドでいくつかの作業を実行したいと思います。問題は、私はメインスレッドをブロックしたくないということです。メインスレッドをブロックせずにExecutorServiceのタイムアウト

ナイーブな実装では、2つのエグゼキュータサービスがあります。 1つはスケジューリング/タイムアウトのためのもので、もう1つは作業を終了する責任があります。

final ExecutorService backgroundExecutor = Executors.newSingleThreadExecutor(); 
final ExecutorService workerExecutor = Executors.newCachedThreadExecutor(); 


backgroundExecutor.execute(new Runnable() { 
    public void run() { 
     Future future = workerExecutor.submit(new Runnable() { 
      public void run() { 
       // do work 
      } 
     }); 
     try { 
      future.get(120 * 1000, TimeUnit.MILLISECONDS); 
     } catch (InterruptedException e) { 
      logger.error("InterruptedException while notifyTransactionStateChangeListeners()", e); 
      future.cancel(true); 
     } catch (ExecutionException e) { 
      logger.error("ExecutionException", e); 
     } catch (TimeoutException e) { 
      logger.error("TimeoutException", e); 
      future.cancel(true); 
     } 
    } 
}); 

他に解決策はありますか?

+0

1つのスレッドがジョブを実行し、もう1つがそれを待っている単一の2つのスレッドプールが単純化されます。それは少なくとも内部のプールを節約しますが、それ以外の場合はあまり役に立ちません。 – Gray

+0

タスクをTimerとExecutorの両方に同時に発行することはできますか?まずrun()に入り、ロックアウトまたは同期化が、タイムアウトとタスク完了の間の調停のどこかで必要になり、それぞれの場合に正しいアクションがとられるようになります。うーん..わからない。 –

+0

あなたのコードでFuture.get()の結果を無視するので、実際に結果をいくつかのスレッドで待つ必要があるのだろうか? –

答えて

2

1度だけ1つのスレッドを実行するためにExecutorServiceは必要ありません。代わりにFutureTaskを作成して、オーバーヘッドなしで同じメリットを得ることができます。

FutureTask<T> future = new FutureTask<T>(callable); 
Thread thread = new Thread(future); 
thread.start(); 
try { 
    future.get(120 * 1000, TimeUnit.MILLISECONDS); 
} ... 

上記のスニペットで呼び出し可能なのはあなたの仕事です。あなたが経由で呼び出し可能にそれを回すことができます(あなたは上記のコードブロックで行うよう)のRunnableをお持ちの場合 :だから、要約する

Callable callable = Executors.callable(runnable, null); 

、あなたのコードが変更される可能性に:

backgroundExecutor.execute(new Runnable() { 
    public void run() { 

     Runnable myRunnable = new Runnable() { 
      public void run() { 
       // do work 
      } 
     } 

     Callable callable = Executors.callable(myRunnable, null); 

     FutureTask<T> future = new FutureTask<T>(callable); 
     Thread thread = new Thread(future); 
     thread.start(); 

     try { 
      future.get(120 * 1000, TimeUnit.MILLISECONDS); 
     } catch (InterruptedException e) { 
      logger.error("InterruptedException while notifyTransactionStateChangeListeners()", e); 
      future.cancel(true); 
     } catch (ExecutionException e) { 
      logger.error("ExecutionException", e); 
     } catch (TimeoutException e) { 
      logger.error("TimeoutException", e); 
      future.cancel(true); 
     } 
    } 
}); 

実行者をシャットダウンする必要はありません。あなたはまだ最終的に他のリソースをクリーンアップしたいかもしれませんが。

関連する問題