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();
}
}
}
}
}