2

我正在用java编写一个程序,其中必须有一些从主线程创建并在其旁边运行的线程(例如3个)。程序一步一步进行。在每个步骤中,主线程首先计算一个时钟并打印它(独占执行),然后其他线程必须检查一些东西(它们的顺序不重要,它们必须同时工作),看看它们是否必须在这个时钟中打印出一些东西与否,这会重复。

如何以简单的方式强制它们之间的这种排序(线程和其他线程的集合)?我必须这样写,我的意思是我不能没有线程。

这就是我想要的输出:

    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

我使用CyclicBarrier. 我定义了一个Clock类,它是一个专门的屏障,它在每一步都更新其内部计数器。这些任务是简单的线程,它们根据当前步骤完成工作,然后等待时钟继续。

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()在同一个对象上。如果滴答声很频繁,此方法确实存在您的工作人员无法在时钟滴答声内完成的小风险,但这是您无法控制的线程调度问题。

如果您必须在主线程再次滴答之前让所有工作人员完成,您可以设置两个Semaphores,我们将其称为okToWorkokToTick。主线程在滴答之前需要okToTick.acquire(X)(其中 X 是工人的数量),这意味着所有 X 个工人都允许它滴答。当它完成滴答时,这okToWork.release(X)意味着它被允许所有 X 工人工作。工作人员在开始工作之前需要okToWork.acquire()从主线程获得许可才能工作,完成后需要okToTick.release()给主线程提供它需要勾选的 X 权限之一。请注意,如果您走这条路线,则okToWork必须将其fair设置为true. 信号量的起始许可计数应该是 0okToWork和 XokToTick这样 Mian 线程就可以开始滴答作响,但工人不必开始工作。

于 2012-12-21T15:13:06.733 回答