为什么我的生产者消费者计划被封锁

时间:2013-08-10 19:41:19

标签: java multithreading producer-consumer

我创建了自己的队列。

Queue.java

public class MyQueue {

    private int size;

    private Queue<String> q;

    public MyQueue(int size ,Queue<String> queue) {
    this.size = size;
    this.q = queue;

    }

    //getter and setter    

    public synchronized void putTail(String s) {

System.out.println(this.size); // It should print 0, 1,2

          while (q.size() != size) {

             try {
                wait();
             }
             catch (InterruptedException e) {
             }
          }
          Date d = new Date();

          q.add(d.toString());

          notifyAll();

       }

}

MyProducer.java

import com.conpro.MyQueue;

public class MyProducer  implements Runnable {

    private final MyQueue queue;

    private final int size; 

    MyProducer(int size,MyQueue q) { this.queue = q; this.size = size; }


    @Override
    public void run() 
    {
        queue.putTail(String.valueOf(Math.random()));
    }

}

MyTest.java

public class MyTest {

    public static void main(String[] args) {

        Queue q = new PriorityQueue<String>();
        MyQueue mq = new MyQueue(3,q);

         MyProducer p = new MyProducer(3,mq);
         MyProducer p1 = new MyProducer(3,mq);
         MyProducer p2 = new MyProducer(3,mq);
         new Thread(p).start();
         new Thread(p1).start();
         new Thread(p2).start();

    }

}

现在我在这里创建了3个制作人。 因此,执行这3行后,队列应该已满。

输出应为:

0
1
2

但它只打印0

为什么?

P.S:我还没有写过制作人代码,因为我还没有到达那里。

3 个答案:

答案 0 :(得分:1)

由于putTail()synchronized,因此三个线程中只有一个可以输入它。然后该线程永远位于while (q.size() != size)循环内,而其他两个线程仍然无法进入该方法。

答案 1 :(得分:1)

问题是所有3个主题都进入wait()但从未通过notifyAll

获得通知

您的代码存在问题但实际上并不是阻塞队列。这就是我期望阻塞队列的作用:

  1. 队列的最大大小为3,从无元素开始
  2. 从制作人处获取内容,大小不是3,添加,不阻止
  3. 从制作人处获取其他内容,大小不是3,添加,不阻止
  4. 从制作人处获取 else ,尺寸不是3,添加,不阻止
  5. 从制作人处获取其他内容,大小现在为3,阻止直到采取行动
  6. 从制作人处获取其他内容,大小仍为3,阻止直到采取行动
  7. 消费者从队列中获取,来自(5)和(6)的线程被通知,并且第一个获得调度获得锁定的时间足以添加他的元素,另一个被迫再次阻止直到另一个消费者从队列中获取。
  8. 以下是你的实际所做的事情:

    1. 队列的最大大小为3,从无元素开始
    2. 从制作人处获取内容,尺寸不是3,阻止wait()而不添加
    3. 从制作人处获取内容,尺寸不是3,阻止wait()而不添加
    4. 从制作人处获取内容,尺寸不是3,阻止wait()而不添加
    5. 在所有3个添加元素的情况下,元素实际上都没有被添加,我们陷入wait()因为所有3都进入while循环,然后什么都没有调用{{1 }}

      您在评论中的修正:

      notifyAll()

      这使它做到了它应该做的事情:如果大小已经达到最大值,则阻止它被告知通过while (q.size() == size) 继续,然后检查大小是否仍然是最大值。对于上面示例中的线程,在收到通知后接收锁(例如步骤6中的线程),它将有机会添加其消息。未收到锁定的线程将在第一个释放锁定后接收锁定,但是大小将再次增加到最大大小,这会导致它再次阻塞。话虽如此,我认为你的方法是一个良好的开端。

      您的代码中的一件事是不正确的是您在添加后调用notify。添加永远不会导致队列大小缩小,但是您要通知notifyAll方法中等待的所有线程继续。没有理由通知正在等待向队列中添加内容的线程,如果你只是在其中添加一些内容,使其达到最大大小。我认为你的意思是通过等待你的最终putTail方法的线程做一些事情,这引导我到下一点:

      您的下一步将是拥有两个锁定对象,而不是始终使用take。这样this方法可以与take方法分开阻止。在put方法中使用wait一个锁,在put中使用notifyAll,然后使用另一个锁定take中的wait take中的方法和notifyAll。这将使您可以单独通知玩家和推杆,而不会像使用put那样立即通知所有人。

答案 2 :(得分:0)

问题出在MyQueueputTail()方法中。你在wait()(当前对象)上调用this,它永远不会被通知。当线程将永远等待。