![](/img/trans.png)
[英]Enforce printing sequence but threads waiting on each other after one iteration
[英]Threads wait for each other after each iteration
我希望线程A通过for循环进行一次迭代,等待线程B通过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
由于您正在使实例方法同步,因此它将尝试获取当前实例的监视器,并且由于所有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();
}
}
如果您确实需要以这种方式解决问题,可以使用下面的代码。 但是正如其他人所提到的,在这种情况下使用线程实际上并没有多大意义。 如果您需要等待各种任务(甚至更好,番石榴的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();
}
}
}
如果要按顺序在三个Runnable之间无限循环,请创建Runnable并将其馈入单个线程的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
}
您需要输出的固定类型,即AX,BX,CX,AX...。 并且,您无法确定线程执行的顺序。
而且,您获得的实际输出基于您的syncronized
关键字。 修复先打印A然后打印B的问题。
您无法预测线程顺序的执行。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.