【问题标题】:problem debugging Producer consumer problem问题调试生产者消费者问题
【发布时间】:2020-01-11 14:56:31
【问题描述】:

我正在尝试了解生产者消费者问题。为了复制这个问题,我编写了以下代码

package com.company;

import java.util.ArrayDeque;
import java.util.Queue;

public class ProducerConsumerProblem {

    private static Queue<Integer> q = new ArrayDeque<>(5);

    public static void main(String args[]) {

        Producer p = new Producer();
        Consumer c = new Consumer();

        Thread t = new Thread( p );
        Thread t1 = new Thread( c );

        t.start();
        t1.start();
    }

    public static class Producer implements Runnable {

        @Override
        public void run() {
            while(true) {
                if (q.size() == 5) {
                    continue;
                }
                System.out.println( "Adding to queue" );
                q.add( 1 );
            }
        }
    }
    public static class Consumer implements Runnable {

        @Override
        public void run() {
            while(true) {
                if (q.size() == 0) {
                    continue;
                }
                System.out.println( "Removing from queue" );
                q.remove();
            }
        }
    }
}

我期待得到类似concurrent exception 的东西,但是当队列为空或队列已满时,代码会停止。我的问题是为什么当队列为空或已满时代码会停止,因为我将消费者和生产者都置于无限循环中,即使它们同时进行错误读取但在稍后的某个时间点它们会进行良好读取并且生产者或消费者都应该工作.请帮我解决一下情况

【问题讨论】:

  • 代码没有停止。两个线程都陷入了无限循环,调用 continue ad infinitum,因为代码不是线程安全的,生产者将 sze 视为 5,而消费者将其视为 0。

标签: java multithreading producer-consumer


【解决方案1】:

这两个线程可能会看到不同的大小,因为您的代码不是线程安全的,并且您的添加和删除操作是在不同的线程上完成的。

当您在线程 1 上执行 q.add( 1 ); 时,它不一定将更新后的数组写入内存(即 RAM),它可能仍在 CPU 寄存器中,并且当这两个线程发生上下文切换时,您的更改第二个线程也可能消失,并且看不到更新的大小。如果您使用同步,则同步块中的所有更改都会在同步块结束时保存到 RAM 中,这样就不会再发生不需要的行为。

由于ArrayDeque 不是线程安全的,您需要外部同步以使您的代码线程安全,或者使用并发数据结构。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-27
    • 2011-08-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多