繁体   English   中英

线程在每次迭代后互相等待

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM