2014-03-30 150 views
0

尽管以下是众所周知的话题,我希望你的想法。 我写了一个小程序如下:所有的生产者都排队,也是消费者。我无法理解为什么是这样。什么情况下它可以完全阻止。生产者/消费者和调试死锁的原因

让我们考虑生产者/消费者正在等待阵列上的锁以及使消费者/生产者退出同步块的原因。我的意思是它必须缓慢移动,但不可能发生僵局。我相信。

这里我有两个问题: 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(); 
      } 
     } 

    } 
} 

它击中如下输出:

Consumer of consumer thread in synchronized block extracted value 0 of index 0 
Producer of producer thread in synchronized block i-1 
Producer of producer thread in synchronized block i-1 
Consumer of consumer thread is waiting i -1 
Consumer of consumer thread is waiting i -1 

回答

2

你的代码是在很多地方不正确。

我希望所有的线程只是例外完成,要么是因为

  • IllegalMonitorException的(调用通知()ProducerConsumer对象 开启,但此ProducerConsumer对象没有同步块)
  • ArrayIndexOfBoundsException(我()方法中可以变成10)

你是否检查过错误输出?

+0

是的你是对的。我在数组上同步并等待其他对象。谢谢。 – Curious

+0

看来你编辑你的代码 - 改变Thread.sleep()等待()。它也不会起作用 - 来自produce()的wait()首先被调用,而来自consume()的notify()永远不会被调用。 – kostya

+0

没有例外,现在我改变了等待并通知上面编辑的数组对象。仍然是同样的僵局。 – Curious

0

Java通过其java.util.concurrent包提供了一个巧妙的并发程序实现。因此,不要试图重新发明轮子,并且弄错一切,您应该使用Concurrent API以更安全的方式处理锁定。这里有一个Producer-Consumer的模拟:

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

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

Producer Consumer问题的死锁原因并不是那么多。如果一个线程锁定了object A并且正在等待锁定object B被释放,而如果其他线程同时锁定了object B并且正在等待object A上的锁定被释放,则会出现死锁情况。

+0

嗨阿曼你是对的,我们可以不必重新发明轮子但是在这里我对它为什么会失败感兴趣。任何方式非常感谢你花时间回答。 – Curious

+0

@bhadram:好的。 :) –