线程同步 - 同步三个线程以打印012012012012 .....无法正常工作

时间:2014-07-23 13:44:09

标签: java multithreading thread-synchronization

我正在尝试同步三个线程来打印012012012012 ....但它无法正常工作。为每个线程分配一个号码,当它从主线程接收到信号时,它会打印该号码。以下程序有问题,我无法捕捉到。

public class Application {
    public static void main(String[] args) {

        int totalThreads = 3;
        Thread[] threads = new Thread[totalThreads];

        for (int i = 0; i < threads.length; i++) {
            threads[i] = new MyThread(i);
            threads[i].start();
        }

        int threadIndex = 0;
        while (true) {
            synchronized(threads[threadIndex]) {
                threads[threadIndex].notify();
            }

            threadIndex++;
            if (threadIndex == totalThreads) {
                threadIndex = 0;
            }
        }
    }
}

class MyThread extends Thread {
    private int i;

    public MyThread(int i) {
        this.i = i;
    }

    @Override
    public void run() {
        while (true) {
            synchronized(this) {
                waitForSignal();
                System.out.println(i);
            }
        }
    }

    private void waitForSignal() {
        try {
            wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

4 个答案:

答案 0 :(得分:3)

您需要更多协调。 notify调用不会立即唤醒线程并强制它继续。相反,可以将notify视为向线程发送电子邮件,让它知道它可以继续。想象一下,如果你想让你的3个朋友按顺序给你打电话。你给朋友1发了一封电子邮件给你打电话,等了一秒钟,发了一封电子邮件给朋友2,等了一秒钟,然后发了一封邮件给朋友3.你认为你会按照确切的顺序打电话吗?

添加更多协调的一种方法是使用一些共享状态来指示它的转向。如果你所有的朋友都可以看到你的房子,你可以在房子的外面放一个号码,表明轮到他们打电话了。每个朋友都会等到他们看到他们的号码,然后打电话。

答案 1 :(得分:0)

这是你的问题:

    int threadIndex = 0;
    while (true) {
        synchronized(threads[threadIndex]) {
            threads[threadIndex].notify();
        }

        threadIndex++;
        if (threadIndex == totalThreads) {
            threadIndex = 0;
        }
    }

主线程以正确的顺序通知所有线程。但是,您的线程是独立工作的。它们可能会或可能不会在特定时间点安排。因此最终结果可能是,线程2在线程1之前的线程1之前到达wait/print锁定。最终的顺序不是由发送通知确定的,而是(实质上)由调度程序确定。

解决方案是以这种方式改变

  1. 主线程正好通知一个线程:thread 0
  2. 每个线程完成他的工作,完成后,通知行中的下一个线程
  3. 显然最后一个线程必须再次通知线程0。

答案 2 :(得分:0)

另一种可能的解决方案:在主线程中,您可以在通知线程(在同一synchronized块中)之后立即等待,如下所示:

synchronized (threads[threadIndex])
{
    threads[threadIndex].notify();
    threads[threadIndex].wait(); // try/catch here
}

在线程的run方法中,您可以在线程完成其工作后使用notifyAll唤醒主线程:

synchronized (this)
{
    waitForSignal();
    System.out.println(i);
    notifyAll();
}

更复杂的解决方案将涉及java.util.concurrent.locks包中的类。

答案 3 :(得分:0)

package threads;

import java.util.concurrent.Semaphore;

public class ZeroEvenOddPrinter {
   class Runner extends Thread{
       Semaphore prev;
       Semaphore next;
       int num = 0;
       public Runner(Semaphore prev,Semaphore next,int num){
           this.prev = prev;
           this.next = next;
           this.num = num;
       }
       @Override
       public void run(){
            while (true) {
                try {
                    Thread.sleep(100);
                    prev.acquire();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

                if (num == 0)
                    System.out.println(0);
                else {
                    System.out.println(num);
                    num = num + 2;
                }
                next.release();
            }
        }
   }
   static public void main(String args[]) throws InterruptedException{
       Semaphore sem1 = new Semaphore(1);
       Semaphore sem2 = new Semaphore(1);
       Semaphore sem3 = new Semaphore(1);
       ZeroEvenOddPrinter zeo = new ZeroEvenOddPrinter();
       Runner t1 = zeo.new Runner(sem1,sem2,0);
       Runner t2 = zeo.new Runner(sem2,sem3,1);
       Runner t3 = zeo.new Runner(sem3,sem1,2);
       sem1.acquire();
       sem2.acquire();
       sem3.acquire();
       t1.start();
       t2.start();
       t3.start();
       sem1.release();
   }
}

这里我使用信号量作为所有三个线程的触发器。最初所有线程都将在sem1,sem2,sem3上被阻止。然后我将释放sem1并且第一个线程将执行然后它将释放第二个线程,依此类推......最好的部分是你将这个逻辑扩展到n个线程。祝你好运!!!