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