Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/306.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 生产者/消费者和调试中死锁的原因_Java_Multithreading - Fatal编程技术网

Java 生产者/消费者和调试中死锁的原因

Java 生产者/消费者和调试中死锁的原因,java,multithreading,Java,Multithreading,虽然下面是大家都知道的话题,但我想听听你的想法。 我写了一个小程序如下:所有的生产者和消费者都排队。我不明白为什么会这样。它可以完全阻止的场景有哪些 让我们考虑生产者/消费者在等待锁定数组,以及让消费者/生产者退出同步块的原因。我的意思是,它必须至少缓慢地移动,但决不能出现僵局。我相信 这里我有两个问题: 1.死锁发生的场景是什么。 2.如何理解引擎盖下发生的事情。我的意思是如何调试 public class ProducerConsumer implements Runnable {

虽然下面是大家都知道的话题,但我想听听你的想法。 我写了一个小程序如下:所有的生产者和消费者都排队。我不明白为什么会这样。它可以完全阻止的场景有哪些

让我们考虑生产者/消费者在等待锁定数组,以及让消费者/生产者退出同步块的原因。我的意思是,它必须至少缓慢地移动,但决不能出现僵局。我相信

这里我有两个问题: 1.死锁发生的场景是什么。 2.如何理解引擎盖下发生的事情。我的意思是如何调试

public class ProducerConsumer implements Runnable {

    boolean producer = false;

    private volatile int i = 0;

    int[] array = new int[10];

    public static String getThreadName() {
        return Thread.currentThread().getName();
    }

    public void producer() {
        try {
            synchronized (array) {
                while (i > 9) {
                    System.out.println("Producer of " + getThreadName()
                            + " is waiting i " + i);
                    array.wait();
                    System.out.println("Producer of " + getThreadName()
                            + " came out of sleep i " + i);
                }
                System.out.println("Producer of " + getThreadName()
                        + " in synchronized block i" + i);
                array[i] = generateRandom();
                System.out.println("Producer of " + getThreadName()
                        + " inserted in array " + array[i] + " index " + i);
                i++;
                array.notifyAll();
            }
            Thread.sleep(100);
        } catch (InterruptedException e) {
            System.out.println("Producer of " + getThreadName()
                    + " interrupted " + e);
        }

    }

    public void consumer() {
        try {
            synchronized (array) {
                while (i < 0) {
                    System.out.println("Consumer of " + getThreadName()
                            + " is waiting i " + i);
                    array.wait();
                    System.out.println("Consumer of " + getThreadName()
                            + " came out of sleep i " + i);
                }
                System.out.println("Consumer of " + getThreadName()
                        + " in synchronized block extracted value " + array[i]
                        + " of index " + i);
                i--;
                array.notifyAll();
            }
            Thread.sleep(100);
        } catch (InterruptedException e) {
            System.out.println("Consumer of " + getThreadName()
                    + " interrupted " + e);
        }

    }

    public static int generateRandom() {
        Random random = new Random();
        return random.nextInt(10);
    }

    public static void main(String[] args) {
        ProducerConsumer pc = new ProducerConsumer();
        for (int i = 0; i < 4; i++) {
            if (i % 2 == 0)
                new Thread(pc, "producer thread").start();
            else {
                new Thread(pc, "consumer thread").start();
            }
        }
    }

    public void run() {
        while (true) {
            if (getThreadName().equalsIgnoreCase("producer thread")) {
                producer();
            } else {
                consumer();
            }
        }

    }
}

您的代码在很多地方都不正确

我希望所有的线程都会有例外,因为

  • IllegalMonitorException(对ProducerConsumer对象调用notify() 但此ProducerConsumer对象上没有同步块)
  • ArrayIndexOfBoundsException(在product()方法中我可以变成10)

您是否检查了错误输出?

Java通过其
Java.util.concurrent
包提供了一个简洁的并发程序实现。因此,您应该使用
Concurrent API
以更安全的方式处理锁定,而不是试图重新发明轮子,并将其全部弄错。下面是一个
生产者-消费者的模拟:

import java.util.Random;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * We want a Producer thread to create random values, and the Consumer thread to
 * consume it. One caveat is that if the Producer has already created a random
 * value, which the Consumer thread hasn't consumed yet, the Producer thread
 * blocks or waits. On the flip side, the Consumer thread waits for the Producer
 * thread to produce some value if the Producer thread hasn't already.
 * <p/>
 * Write a Program to simulate such a situation.
 */

public class ProducerConsumerCommunication
{
  private volatile boolean running = true;
  private ArrayBlockingQueue<Integer> buffer = new ArrayBlockingQueue<>(1);
  private Random random = new Random(System.currentTimeMillis());

  public ProducerConsumerCommunication()
  {
    ExecutorService service = Executors.newCachedThreadPool();
    service.execute(new ProducerTask());
    service.execute(new ConsumerTask());
    service.shutdown();
  }

  public static void main(String[] args)
  {
    new ProducerConsumerCommunication();
  }

  private class ProducerTask implements Runnable
  {
    public void run()
    {
      while (running)
      {
        try
        {
          Thread.sleep(random.nextInt(2000));
          Integer value = random.nextInt();
          buffer.put(value); // Blocks if buffer is full.
          System.out.println("Value Put: " + value);
        }
        catch (InterruptedException e)
        {
          e.printStackTrace();
        }
      }
    }
  }

  private class ConsumerTask implements Runnable
  {
    public void run()
    {
      while (running)
      {
        try
        {
          Thread.sleep(random.nextInt(2000));
          Integer value = buffer.take(); // Blocks if buffer is empty.
          System.out.println("Value Taken: " + value);
        }
        catch (InterruptedException e)
        {
          e.printStackTrace();
        }
      }
    }
  }
}
import java.util.Random;
导入java.util.concurrent.ArrayBlockingQueue;
导入java.util.concurrent.ExecutorService;
导入java.util.concurrent.Executors;
/**
*我们希望生产者线程创建随机值,消费者线程创建随机值
*消费它。一个警告是,如果制作人已经创建了一个随机
*值,消费者线程尚未消费该值,生产者线程
*阻塞或等待。另一方面,消费者线程等待生产者
*线程来产生一些值,如果生产者线程还没有。
*

*编写一个程序来模拟这种情况。 */ 公共类产品消费通信 { private volatile boolean running=true; 专用ArrayBlockingQueue缓冲区=新的ArrayBlockingQueue(1); 私有随机=新随机(System.currentTimeMillis()); 公共产品消费沟通(英文) { ExecutorService=Executors.newCachedThreadPool(); service.execute(newproducertask()); 执行(新的ConsumerTask()); service.shutdown(); } 公共静态void main(字符串[]args) { 新产品消费沟通(); } 私有类ProducerTask实现可运行 { 公开募捐 { (跑步时) { 尝试 { Thread.sleep(random.nextInt(2000)); 整数值=random.nextInt(); buffer.put(value);//如果缓冲区已满,则阻塞。 System.out.println(“值Put:+Value”); } 捕捉(中断异常e) { e、 printStackTrace(); } } } } 私有类ConsumerTask实现可运行 { 公开募捐 { (跑步时) { 尝试 { Thread.sleep(random.nextInt(2000)); 整数值=buffer.take();//如果缓冲区为空,则阻塞。 System.out.println(“获取的值:“+值”); } 捕捉(中断异常e) { e、 printStackTrace(); } } } } }

试着运行它,看看使用并发API实现这样的场景是多么容易和直观。它还可以保持代码整洁,让您专注于手头的问题


生产者消费者问题中出现死锁的原因并不多。如果一个线程锁定了
对象A
并等待释放
对象B
上的锁,而另一个线程同时锁定了
对象B
并等待释放
对象A
上的锁,则会出现死锁情况。

是的,您是正确的。我在数组上进行了同步,正在等待其他对象。谢谢。似乎您编辑了代码,将Thread.sleep()更改为wait()。它也不起作用-首先调用product()中的wait(),而永远不会调用consume()中的notify()。没有例外,现在我更改了上面编辑的数组对象上的wait和notify。仍然是相同的死锁。还有一个问题-您应该检查synchronized block中i的值,否则它可能在进入synchronized block之前被更改,还有一件事-您应该使用notifyAll()并在一个循环中检查条件(例如while(i<9){…})嗨,阿曼,你说得对,我们不必重新发明轮子,但我感兴趣的是为什么它会失败。无论如何,非常感谢你花时间回答。
import java.util.Random;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * We want a Producer thread to create random values, and the Consumer thread to
 * consume it. One caveat is that if the Producer has already created a random
 * value, which the Consumer thread hasn't consumed yet, the Producer thread
 * blocks or waits. On the flip side, the Consumer thread waits for the Producer
 * thread to produce some value if the Producer thread hasn't already.
 * <p/>
 * Write a Program to simulate such a situation.
 */

public class ProducerConsumerCommunication
{
  private volatile boolean running = true;
  private ArrayBlockingQueue<Integer> buffer = new ArrayBlockingQueue<>(1);
  private Random random = new Random(System.currentTimeMillis());

  public ProducerConsumerCommunication()
  {
    ExecutorService service = Executors.newCachedThreadPool();
    service.execute(new ProducerTask());
    service.execute(new ConsumerTask());
    service.shutdown();
  }

  public static void main(String[] args)
  {
    new ProducerConsumerCommunication();
  }

  private class ProducerTask implements Runnable
  {
    public void run()
    {
      while (running)
      {
        try
        {
          Thread.sleep(random.nextInt(2000));
          Integer value = random.nextInt();
          buffer.put(value); // Blocks if buffer is full.
          System.out.println("Value Put: " + value);
        }
        catch (InterruptedException e)
        {
          e.printStackTrace();
        }
      }
    }
  }

  private class ConsumerTask implements Runnable
  {
    public void run()
    {
      while (running)
      {
        try
        {
          Thread.sleep(random.nextInt(2000));
          Integer value = buffer.take(); // Blocks if buffer is empty.
          System.out.println("Value Taken: " + value);
        }
        catch (InterruptedException e)
        {
          e.printStackTrace();
        }
      }
    }
  }
}