2

Javaスレッドについて学ぼうとすると、通常、まったく同じクラスのコード例に出くわしますwait()notify()実際、ほとんどすべてのコード例は生産者/消費者の例です)。さまざまな例を調べた後、残念ながら、必要なケースを見つけることができませんでした。

  • マネージャースレッドは、最初にn個のスレッドを作成し(そしてそれらを開始し)、そこでhttpget要求が単一のスレッドで実行されます。
  • 単一のワーカースレッドの場合、その寿命を完了するのに約20〜30秒かかります。
  • ここで、私のマネージャースレッドは、どのワーカーが終了したかを認識し、終了スレッドを新しいスレッドに置き換えます。

私はそのようなアプローチについて考えました(nを5とします):

List<Runnable> runnables = new ArrayList<Runnable>();
for(int i = 0 ; i < 5 ; i++){
    runnables.add(new MyWorker(params));
}
for(Runnable myWorker : runnables){
   myWorker.run();
}

wait()複数のオブジェクトをサポートしていないので、ここから先に進むことはできません。別の解決策は、各ワーカーのisFinishedフラグを呼び出しているマネージャースレッドでビジーウェイトを実装することです。しかし、これが良いアプローチかどうかはわかりません(これがリソースの浪費であることがわかっている限り)

4

2 に答える 2

3

Java 6以降には、エグゼキュータフレームワークの形式ですぐに使用できるツールがあります。

スレッドの固定プールが必要なので、最善の策は次を使用することです。

ExecutorService service = Executors.newFixedThreadPool(5);

次に、メソッド(インターフェースによって定義される)Runnableを使用してインスタンスを送信できます。それらはワークキューに送信され、プール内のスレッドが使用可能になるとすぐにデキューされます。.execute()Executor

個々のスレッド作業メソッドが値を返す場合(つまり、それらが実装する場合)、メソッド(によって定義され、拡張するインターフェイスも)Callable<Something>を使用できます。このメソッドから、計算された値が返されます。.submit()ExecutorServiceExecutorFuture<Something>.get()

スレッドプールの終了はさまざまな方法で行われます。.shutdown()これは最も基本的な方法であり、まだアクティブなスレッドが終了するのを同期的に待機します(そして新しいジョブが送信されないようにします)。

Javadoc:ExecutorsExecutorServiceThreadPoolExecutor

その他のリンク:スレッド関連のすべてのもののために購入する必要がある本(ただし、Java 7は対象外ですForkJoinPool)。

PS:幸運なことに、上記の本のサンプルの章(PDF)はタスクの実行をカバーしています;)

于 2013-01-01T22:47:50.413 に答える
1

あなたはあなたがやろうとしていることを達成するために使用semaphoreし、アプローチすることができます。wait/notifyアプローチは次のとおりです。

  1. semaphore一度に許可されるスレッドの最大数でを初期化します。
  2. でタスクが使用可能になるまで待ちますqueue
  3. を取得しsemaphoreます。
  4. タスクを実行し、終了したらリリースしsemaphoreます。

4つのステップすべてを永久にwhileループに入れると、タスク実行者の準備が整います。ThreadPoolExecuter@fgeは、同じことを実行でき、より最適化されたものがすでに存在すると述べたため、これは学習目的のみです。

import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.Semaphore;

public class ThreadExecuter extends Thread {

    Queue<Runnable> tasks = new LinkedList<Runnable>();
    Semaphore s;
    Object bin = new Object();

    public ThreadExecuter(int n) {
        s = new Semaphore(n);
    }

    public void addTask(Runnable r) {
        synchronized (bin) {
            tasks.add(r);
            bin.notifyAll();
        }
    }

    public void run() {
        while (true) {
            try {
                final Runnable r;
                synchronized (bin) {
                    while (tasks.isEmpty())
                        bin.wait();
                    r = tasks.poll();
                }

                s.acquire();
                new Thread() {
                    public void run() {
                        r.run();
                        s.release();
                    }
                }.start();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

    }
}

主な方法は次のようになります。

import java.util.Random;

public class ThreadTest {

    /**
     * @param args
     */
    public static void main(String[] args) {
            /* to make maximum 10 threads each running 1 runnable */
        ThreadExecuter executer = new ThreadExecuter(10);
        executer.start();

        for(int i = 0; i < 5000; i++) {
                    /* add task in executer, this is non blocking */
            executer.addTask(new Runnable() {
                @Override
                public void run() {
                    System.out.println("Task Executed in " 
                                        + Thread.currentThread().getId());
                    try {
                        Thread.sleep(new Random().nextInt(8000));
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    }

}
于 2013-01-01T22:50:59.710 に答える