2

メインスレッドから作成され、その横で実行されるいくつかのスレッド(たとえば3)が必要なプログラムをJavaで作成しています。プログラムは段階的に進みます。各ステップで、メインスレッドは最初にクロックをカウントして出力します (排他的に実行します)。次に、他のスレッドはすべて何かをチェックする必要があります (順序は重要ではなく、同時に動作する必要があります)。このクロックで何かを出力する必要があるかどうかを確認します。かどうか、これが繰り返されます。

簡単な方法でこの順序付けを強制するにはどうすればよいですか (メインスレッドと他のスレッドのコレクション)。このように書かなければなりません。つまり、スレッドなしでは行けないということです。

これは私が出力に欲しいものです:

    Master Clock : 0
      Core 2 started its first task of 7 time units
      Core 0 started its first task of 9 time units
      Core 1 started its first task of 6 time units
    Master Clock : 1
    Master Clock : 2
    Master Clock : 3
    Master Clock : 4
    Master Clock : 5
    Master Clock : 6
      Core 1 started context switch
    Master Clock : 7
      Core 2 started context switch
    Master Clock : 8
      Core 1 started a new task of 9 time units
    Master Clock : 9
      Core 2 started a new task of 10 time units
      Core 0 started context switch
    Master Clock : 10
    Master Clock : 11
      Core 0 started a new task of 10 time units
    Master Clock : 12
    Master Clock : 13
    Master Clock : 14
    Master Clock : 15
    Master Clock : 16
    Master Clock : 17
      Core 1 started context switch
    Master Clock : 18
    Master Clock : 19
      Core 1 started a new task of 8 time units
      Core 2 started context switch
    Master Clock : 20
    Master Clock : 21
      Core 0 completed a total of 2 tasks
      Core 2 started a new task of 7 time units
    Master Clock : 22
    Master Clock : 23
    Master Clock : 24
    Master Clock : 25
    Master Clock : 26
    Master Clock : 27
      Core 1 completed a total of 3 tasks
    Master Clock : 28
      Core 2 completed a total of 3 tasks
4

3 に答える 3

4

を使用してこれを作成しましたCyclicBarrierClockすべてのステップで内部カウンターを更新する特殊なバリアであるクラスを定義しました。タスクは、現在のステップに応じてジョブを実行し、時計が続くのを待つ単純なスレッドです。

package stackoverflow;

import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class ClockTasks {

    public static void main(String[] args) {

        List<Task> tasks = new LinkedList<Task>();
        String[] tasksLabels = new String[] {"Physics", "Audio", "Video"};

        Clock clock = new Clock(tasksLabels.length, new Counter());

        for (String s: tasksLabels) {
            Task task = new Task(s, clock);
            tasks.add(task);
            task.start();
        }

    }

    static class Counter implements Runnable {
        volatile int step = 0;

        @Override
        public void run() {
            step++;
        }

        public int getStep() {
            return step;
        }
    }

    static class Clock extends CyclicBarrier {
        private Counter counter;

        public Clock(int parties, Counter counter) {
            super(parties, counter);
            this.counter = counter;
        }

        int getStep() {
            return counter.getStep();
        }
    }

    static class Task extends Thread {

        String name;
        Clock clock;
        boolean running = true;
        Random random = new Random();

        Task(String name, Clock clock) {
            this.clock = clock;
            this.name = name;
        }

        boolean checkStep(int step) {
            return true;
        }

        @Override
        public void run() {
            while (running) {
                try {
                    doIt(clock.getStep());
                    clock.await();
                } catch (InterruptedException e) {
                    running = false;
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    running = false;
                    e.printStackTrace();
                }
            }
        }

        public void doIt(int step) throws InterruptedException {
            System.out.println(name + ": step " + step);
            // Simulate a busy task
            Thread.sleep(random.nextInt(1000));
        }
    }

}
于 2012-12-21T14:58:09.177 に答える
3

これは、CyclicBarrierを使用して実行できます。

メインスレッドはを作成し、それにクロックを更新するCyclicBarrierを与えることができます。Runnableを各スレッドに渡しCyclicBarrierます。各スレッドは現在のクロックを処理してから、を呼び出しますawait

于 2012-12-21T14:57:31.893 に答える
1

それはあなたのクロック周波数に依存します。頻度が高すぎない場合は、すべてのワーカー スレッドwait()が作業を完了するたびに共有オブジェクトを使用できます。メインスレッドが作業に戻ることを望む場合、それはnotifyAll()同じオブジェクトに対して行うことができます。この方法では、ティックが頻繁に発生する場合、ワーカーがクロック ティック内に終了しないという小さなリスクがありますが、これは制御できないスレッド スケジューリングの問題です。

メイン スレッドが再び動作する前にすべてのワーカーを終了させる必要がある場合は、2 つの を設定できます。これをおよびSemaphoreと呼びます。メインスレッドは、ティックする前に(X はワーカーの数) する必要があります。つまり、すべての X ワーカーがティックする許可を与える必要があります。ティックが完了すると、すべての X ワーカーに作業の許可が与えられたことを意味します。ワーカーは、作業を開始する前にメイン スレッドから作業許可を取得する必要があり、作業が完了したら、メイン スレッドに必要な X 許可の 1 つを与える必要があります。この方法を使用する場合、は に設定する必要があることに注意してください。セマフォの開始許可カウントは、0 の場合は 0 、Xの場合は X にする必要があります。okToWorkokToTickokToTick.acquire(X)okToWork.release(X)okToWork.acquire()okToTick.release()okToWorkfairtrueokToWorkokToTickミアンスレッドがティックを開始できるようにしますが、ワーカーは作業を開始する必要はありません。

于 2012-12-21T15:13:06.733 に答える