Java wait - 在 while 循环内/外同步

标签 java multithreading wait

我正在解决消费者/生产者问题,以熟悉 Java 中的并发问题。我的问题可能与 C/P 问题本身相邻。在下面的代码片段中,如果我使用版本 1,程序似乎运行良好,而使用版本 2,我似乎在一段可变的时间后陷入死锁。

我只会发布 Producer 类,因为不需要 Consumer 类。

  • 缓冲区是生产者存放其输出的地方
  • 我只是将 1 的整数添加到其中
  • while(true)是让线程持续运行

我的问题是:我知道在Java API中调用wait()的结构是:synchronized -> while -> wait。但是在 while -> synchronized -> wait 的情况下会发生什么?如果在wait()期间,Consumer调用notifyAll()并且Producer再次唤醒,那么代码不会从调用wait()的地方继续,最终会到达while(buffer.remainingCapacity() == 0) ?

我已经进行了挖掘,看看以前是否有人问过这个问题,但找不到任何具体的内容。

版本 1

public class Producer extends Thread {
    ArrayBlockingQueue<Integer> buffer = new ArrayBlockingQueue<>(10);
    public Producer(ArrayBlockingQueue<Integer> buffer) {
        this.buffer = buffer;
    }

    @Override
    public void run() {
        while (true) {
            synchronized(buffer) {
                while (buffer.remainingCapacity() == 0) {
                    try {
                        buffer.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
            try {
                synchronized (buffer) {
                    buffer.add(1);
                    System.out.println("Producer active with remaining capacity: " + buffer.remainingCapacity());
                    buffer.notifyAll();
                }
            } catch (IllegalStateException ex) {
                ex.printStackTrace();
            }
        }
    }
}

版本 2

public class Producer extends Thread {
    ArrayBlockingQueue<Integer> buffer = new ArrayBlockingQueue<>(10);

    public Producer(ArrayBlockingQueue<Integer> buffer) {
        this.buffer = buffer;
    }

    @Override
    public void run() {
        while (true) {
            while (buffer.remainingCapacity() == 0) {
                synchronized (buffer) {
                    try {
                        buffer.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
            try {
                synchronized (buffer) {
                    buffer.add(1);
                    System.out.println("Producer active with remaining capacity: " + buffer.remainingCapacity());
                    buffer.notifyAll();
                }
            } catch (IllegalStateException ex) {
                ex.printStackTrace();
            }
        }
    }
}

只是为了解决这个问题,这是该问题的另一个版本代码,该代码似乎有效。我只是将其放在这里,以防对其他人有帮助,或者是否有人可以告诉我它是否错误以及原因。与上面的版本相比,这个版本的 wait 和 notificationAll 方法在代码中的位置发生了“翻转”。

while(true) {
            while(buffer.remainingCapacity() == 0){
                synchronized (buffer){
                    buffer.notifyAll();
                }
            }
            try {
                buffer.add(1);
                System.out.println("Producer active with remaining capacity: " + buffer.remainingCapacity());
            } catch (IllegalStateException ex) {
                synchronized (buffer){
                    try {
                        buffer.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

最佳答案

同步要考虑的事情是“什么操作需要是原子的?”在您的示例中,检查然后等待必须是原子的。否则,请考虑以下事件顺序:

  • 线程 1:检查已执行但失败
  • 线程2:更新缓冲区以更改检查结果
  • 线程2:调用通知
  • 线程1:WAITING调用

在这种情况下,Thread1 错过了通知并阻塞,直到另一个通知到来。将检查放在同步块(synchronized block)内可以消除这种可能性,因为在 Thread1 调用 wait 之前,Thread2 无法调用 notification。

关于Java wait - 在 while 循环内/外同步,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27218779/

相关文章:

java - 长和纬度值未传递给 .createPoint(new Cooperative(long, lat));

Java Swing 处理状态

c++ - 无法将套接字对象移动到 std::vector

asynchronous - Flutter,功能需要等到数据可用

c - 如何等待非子进程退出

java - 使用 ACTION_IMAGE_CAPTURE Intent 时如何正确捕获 Android 相机 Activity 的错误

java - 使用 Java 获取 Open Office 中的工作表数量

java - 有没有人得到 jax-ws-catalog.xml 来在 Metro 上本地解析 schemaLocation?

Java并发

java - 等待上一个函数执行完毕