管理线程的顺序

时间:2012-12-21 14:07:31

标签: java concurrency

我正在用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

3 个答案:

答案 0 :(得分: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));
        }
    }

}

答案 1 :(得分:3)

可以使用CyclicBarrier完成此操作。

主线程可以创建CyclicBarrier并为其提供更新时钟的Runnable。将CyclicBarrier传递给每个线程,该线程将处理当前时钟,然后调用await

答案 2 :(得分:1)

这取决于您的时钟频率。如果它不是太频繁,那么只要完成他们的工作,就可以拥有一个共享对象,使所有工作线程都wait()。当主线程希望它们重新开始工作时,它可以在同一个对象上notifyAll()。如果滴答频繁,这种方法确实会导致您的工作人员无法在时钟滴答内完成的小风险,但这是您无法控制的线程调度问题。

如果您必须让所有工作人员在主线程再次打勾之前完成,您可以设置两个Semaphore,我们将调用okToWorkokToTick。在打勾之前,主线程需要okToTick.acquire(X)(其中X是工人的数量),这意味着所有X工作者都允许其打勾。当它完成滴答时,它将okToWork.release(X)意味着它被允许所有X工作者工作。在开始工作之前,工作人员需要okToWork.acquire()从主线程获得权限才能工作,完成后需要okToTick.release()为主线程提供所需的X权限之一。请注意,如果您选择此路线,okToWork必须将fair设置为true。对于okToWork,信号量的起始许可计数应为0,对于okToTick应为X,以便mian线程可以开始计时,但工人不必开始工作。