2016-06-16 11 views
0

終了しないJavaスレッドを作成するにはどうすればよいのでしょうか。終了しないスレッドを作成する

ExecutorService pool = Executors.newFixedThreadPool(3); 
for (int i = 0; i < numThreads; ++i) { 
    pool.submit(new Task()); 
} 
pool.shutdown(); 

とタスクは私のアプローチと私が持っている2つの懸念があり、この

public class Task { 
    ... 
    public void run() { 
     while(true) { } 
    } 
} 

のようなものになります:

    を 現在、私は基本的には基本的にのように見える「ランナー」を持っています
  1. 仕事をした後に戻ってくるタスクを作成し、最小限の作業を行うスレッドを作成し続ける必要がありますか?オーバーヘッドについては心配していますが、測定方法はわかりません。

  2. スレッドが無限にループしている場合、強制的に実行可能ファイルを終了すると、それらのスレッドはシャットダウンされ、クリーンアップされますか?いくつかのテストの後で、ExecutorServiceを含むコードが強制的にシャットダウンされると、InterruptExceptionがスローされているようには見えません。

EDIT: は手の込んだには、タスクは、私はキューが、ここで使用するキーでブロックし、@Dレバントに同意

public void run() { 
    while(true) { 
     // Let queue be a synchronized, global queue 
     if (queue has an element) { 
      // Pop from queue and do a very minimal amount of work on it 
      // Involves a small amount of network IO (maybe 10-100 ms) 
     } else { 
      sleep(2000); 
     } 
    } 
} 
+0

両方の質問は、実際には 'while(true){}'ブロックの内容に依存します。それは回転している、眠っている、I/Oをブロックしている、または何ですか? – erickson

+1

スレッドプールを作成することは無意味ですが、スレッドごとにforever-loopを実行するだけです。あなたが何をしようとしているのか、それはもっと良いアイデアかもしれません:キューから読むために1つの専用のスレッドを持っている。それが要素を取得すると、その要素を短い実行 'Task'を作成して処理し、スレッドプールで実行します。 –

+0

Hey @erickson:編集を追加しました。基本的には、スリープ状態になるか、ネットワークIOでブロックされます(計算は最小限に抑えられます)。 – Lycus

答えて

0

のように見えます。ブロッキングキューでは、キュー空またはキュー全体のシナリオを処理する必要はありません。あなたのTaskクラスで

while(true) { 
     // Let queue be a synchronized, global queue 
     if (queue has an element) { 
      // Pop from queue and do a very minimal amount of work on it 
      // Involves a small amount of network IO (maybe 10-100 ms) 
     } else { 
      sleep(2000); 
     } 
    } 

その本当によくないアプローチ、その非効率的なあなたのwhileループは、ポーリングが連続しているので、でもあなたはまだスレッド睡眠を()置くが、しているのもオーバーヘッド不必要なコンテキストスイッチは、スレッドがウェイクアップしてスリープするたびに切り替わります。

私の意見では、エグゼキュータを使用するあなたのアプローチは、あなたのケースに適しています。スレッドの作成は明らかにコストのかかるプロセスであり、エグゼクティブは異なるタスクに同じスレッドを再利用する柔軟性を提供します。 execute(Runnable)またはsubmit(Runnable/Callable)にタスクを渡すことができます。その後、Executors内部では休憩が取られます。 Executorsは、内部的にブロッキング・キューの概念のみを使用します。

ThreadPoolExecutorクラスを使用して独自のスレッドプールを作成し、そのコンストラクタに必要なパラメータを渡すこともできます。ここでは、独自のブロッキングキューを渡してタスクを保持できます。残りのスレッド管理は、コンストラクタの設定パスに基づいてそれに注意を払います。したがって、設定パラメータについて本当に自信があれば、それを実行することができます。

最後に、Javaの組み込みExecutorsフレームワークを使用したくない場合は、BlockingQueueを使用してタスクを保持し、このブロッキングキューからタスクを取得するスレッドを開始することでソリューションを設計できます実行するには、以下のハイレベル実装があります。

class TaskRunner { 
    private int noOfThreads; //The no of threads which you want to run always 
    private boolean started; 
    private int taskQueueSize; //No. of tasks that can be in queue at a time, when try to add more tasks, then you have to wait. 
    private BlockingQueue<Runnable> taskQueue; 
    private List<Worker> workerThreads; 

    public TaskRunner(int noOfThreads, int taskQueueSize) { 
     this.noOfThreads = noOfThreads; 
     this.taskQueueSize = taskQueueSize; 
    } 

    //You can pass any type of task(provided they are implementing Runnable) 
    public void submitTask(Runnable task) { 
     if(!started) { 
     init(); 
     } 
     try { 
     taskQueue.put(task); 
     } catch (InterruptedException e) { 
     e.printStackTrace(); 
     } 
    } 

    public void shutdown() { 
     for(Worker worker : workerThreads){ 
     worker.stopped = true; 
     } 
    } 

    private void init() { 
     this.taskQueue = new LinkedBlockingDeque<>(taskQueueSize); 
     this.workerThreads = new ArrayList<>(noOfThreads); 
     for(int i=0; i< noOfThreads; i++) { 
     Worker worker = new Worker(); 
     workerThreads.add(worker); 
     worker.start(); 
     } 
    } 

    private class Worker extends Thread { 
     private volatile boolean stopped; 
     public void run() { 
     if(!stopped) { 
      try { 
       taskQueue.take().run(); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
     } 
    } 
} 

class Task1 implements Runnable { 
    @Override 
    public void run() { 
     //Your implementation for the task of type 1 
    } 
} 

class Task2 implements Runnable { 
    @Override 
    public void run() { 
     //Your implementation for the task of type 2 
    } 
} 

class Main { 

    public static void main(String[] args) { 
     TaskRunner runner = new TaskRunner(3,5); 
     runner.submitTask(new Task1()); 
     runner.submitTask(new Task2()); 
     runner.shutdown(); 
    } 
} 
関連する問題