这是我的代码,运行我的代码时输出都是不同的。有时会通知所有三个阅读器,输出为:

等待计算...

等待计算...

等待计算...

已完成

总计为:4950Thread-1

总数是:4950Thread-2

总数是:4950线程-0

有时只会通知两个或一个读者。
问题是什么?

class Reader extends Thread {
    Calculator c;

    public Reader(Calculator calc) {
        c = calc;
    }

    public void run() {
        synchronized (c) {
            try {
                System.out.println("Waiting for calculation...");
                c.wait();
            } catch (InterruptedException e) {
            }
            System.out.println("Total is: " + c.total +Thread.currentThread().getName());
        }
    }

    public static void main(String[] args) {
        Calculator calculator = new Calculator();
        new Reader(calculator).start();
        new Reader(calculator).start();
        new Reader(calculator).start();
        new Thread(calculator).start();
    }
}

class Calculator implements Runnable {
    int total;

    public void run() {
        synchronized (this) {
            for (int i = 0; i < 100; i++) {
                total += i;
            }
            System.out.println("Finished");
            notifyAll();
        }
    }
}


根据元发布,这个问题被认为是重复的,但是被欺骗的两个“重复”根本不适用。 How to use wait and notify in Java?提醒用户,如果您确实要等待同一对象,则必须在该对象上进行同步。但是此解决方案已在执行此操作。 Java: notify() vs. notifyAll() all over again提醒用户notifynotifyAll之间的差异,甚至与问题无关。

最佳答案

我能够重现该问题-基本上,如果您的计算机速度太快或调度不正确,计算器可能会在读者有机会进行同步和等待之前完成操作。


  c:\ files \ j> java Reader
  等待计算...
  等待计算...
  已完成
  等待计算...
  总数是:4950Thread-2
  总数是:4950线程-0


为避免这种情况,您应该在执行计算之前验证所有阅读器均已准备就绪。

c:\ files \ j> java Reader
等待计算...
等待读者...目前1
等待计算...
等待计算...
已完成
总计为:4950Thread-1
总数是:4950Thread-2
总数是:4950线程-0

这是我的代码

import java.util.concurrent.atomic.AtomicInteger; // corsiKa added import
class Reader extends Thread {

    static class Calculator implements Runnable {
        int total;
        AtomicInteger readers = new AtomicInteger(0); // corsiKa added atomicinteger

        public void run() {
            // corsiKa added while
            while(readers.get() < 3) {
                System.out.println("Waiting for readers... currently " + readers.get());
                try { Thread.sleep(100); } catch(InterruptedException e) { }
            }
            synchronized (this) {
                for (int i = 0; i < 100; i++) {
                    total += i;
                }
                System.out.println("Finished");
                notifyAll();
            }
        }
    }

    Calculator c;

    public Reader(Calculator calc) {
        c = calc;
    }

    public void run() {
        synchronized (c) {
            try {
                c.readers.incrementAndGet(); // corsiKa added increment
                System.out.println("Waiting for calculation...");
                c.wait();
            } catch (InterruptedException e) {
            }
            System.out.println("Total is: " + c.total +Thread.currentThread().getName());
        }
    }

    public static void main(String[] args) {
        Calculator calculator = new Calculator();
        new Reader(calculator).start();
        new Reader(calculator).start();
        new Reader(calculator).start();
        new Thread(calculator).start();
    }
}

07-27 18:00