我希望线程A在for循环中迭代一次,等待线程B循环一遍for for循环并等待线程C循环一遍for循环。然后一遍又一遍。我试着使用wait()和notify(),但我无处可去。怎么能解决这个问题?
public class Test extends Thread {
static int counter=0;
synchronized public void run() {
for(int i=0; i<4; i++) {
System.out.println(Thread.currentThread().getName()+" "+counter++);
}
}
public static void main(String[] args) throws InterruptedException {
Test t1 = new Test();
Test t2 = new Test();
Test t3 = new Test();
t1.setName("A");
t2.setName("B");
t3.setName("C");
t1.start();
t2.start();
t3.start();
}
}
它应该将以下内容打印到控制台:
A 0
B 1
C 2
A 3
B 4
C 5
A 6
B 7
C 8
A 9
B 10
C 11
但是使用代码我得到一个像这样的随机输出:
A 0
A 3
A 4
A 5
C 2
C 6
C 7
B 1
C 8
B 9
B 10
B 11
答案 0 :(得分:0)
由于您正在使实例方法同步,它将尝试获取当前实例的监视器,并且由于所有3个线程都是不同的实例,因此所有获取和释放监视器都是独立的。您应该考虑使用join()
等待其他线程。
你可以做类似的事情 -
public class Test extends Thread {
static int counter=0;
Test lockTest;
public Test(){}
public Test(Test t) {
this.lockTest = t;
}
public void run() {
for(int i=0; i<4; i++) {
System.out.println(Thread.currentThread().getName()+" "+counter++);
}
if(lockTest != null)
lockTest.join(); //wait for other thread
}
public static void main(String[] args) throws InterruptedException {
Test t1 = new Test(null);
Test t2 = new Test(t1);
Test t3 = new Test(t2);
t1.setName("A");
t2.setName("B");
t3.setName("C");
t1.start();
t2.start();
t3.start();
}
}
答案 1 :(得分:0)
如果你真的需要这样解决,你可以使用下面的代码。但正如其他人所说,在这种情况下使用线程并没有多大意义。如果你需要等待来自各种任务的计算结果(甚至更好,guava ListenableFuture),我建议调查Future类和ExecutorService.submit。可能是CyclicBarrier,CountDownLatch,某种阻塞队列......很难说不知道你的真正的用例,而不是神秘的代码问题。
public class Test extends Thread {
static int counter=0;
private Test previous;
public void run() {
for(int i=0; i<4; i++) {
synchronized(previous) {
try {
previous.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+" "+counter++);
synchronized(this) {
this.notify();
}
}
}
public static void main(String[] args) throws InterruptedException {
Test t1 = new Test();
Test t2 = new Test();
Test t3 = new Test();
t1.setName("A");
t2.setName("B");
t3.setName("C");
t1.previous = t3;
t2.previous = t1;
t3.previous = t2;
t1.start();
t2.start();
t3.start();
synchronized(t3) {
t3.notify();
}
}
}
答案 2 :(得分:0)
如果你想按顺序在三个Runnables之间无休止地循环,创建Runnables并将它们提供给单个线程的ThreadPoolExecutor或ExecutorService,如下所示:
while (running)
{
ExecutorService threadPool = Executors.newSingleThreadExecutor(Executors.defaultThreadFactory());
threadPool.execute(new RunnableA());
threadPool.execute(new RunnableB());
threadPool.execute(new RunnableC());
threadPool.shutdown();
threadPool.awaitTermination();//put in a try/catch, omitted for brevity
}
这就是你真正想要的。请注意,上面的ExecutorService具有无限制的队列,因此您必须限制提交任务的速率或使用允许您使用有界队列的ThreadPoolExecutor之类的东西。或者你可以在每个循环中创建一个新的ExecutorService,在每个循环后调用shutdown()然后在循环结束时等待终止。
如果您没有意识到这一点,上面的每个RunnableA / B / C类应该是这样的:
public class RunnableA implements Runnable()
{
public void run()
{
//do stuff, ie, your loop
}
}
当然总是可以选择将所有三个循环放在一个方法体中,这样做的优点是更简单。
public void doStuff()
{
//loopA
//loopB
//loopC
}
答案 3 :(得分:-1)
您想要一种固定类型的输出,即A X,B X,C X,A X,....并且,您无法修复线程执行的顺序。
而且,您获得的实际结果取决于您的syncronized
关键字。哪个修复了第一个A将被打印然后B,依此类推。
您无法预测线程顺序的执行。