0

我创建了自己的队列。

队列.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

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

}

我的测试.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 个 producer 。所以在执行这 3 行之后,队列应该是满的。

输出应该是:

0
1
2

但它只是打印0

为什么?

PS:我只写了生产者代码,因为我还没有到达那里。

4

3 回答 3

1

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

您的代码存在问题,并没有真正使其成为阻塞队列。这是我希望阻塞队列做的事情:

  1. 队列的最大大小为 3,从没有元素开始
  2. 从生产者那里得到一些东西,大小还不是3,添加它,不要阻塞
  3. 从生产者那里得到其他东西,大小还不是3,添加它,不要阻塞
  4. 从生产者那里得到其他东西,大小还不是3,添加它,不要阻塞
  5. 从生产者那里得到其他东西,大小现在是 3,阻塞直到拿走东西
  6. 从生产者那里得到其他东西,大小仍然是 3,阻塞直到有东西被拿走
  7. 消费者从队列中取出,通知来自(5)和(6)的线程,第一个被调度的线程获得足够长的锁以添加他的元素,另一个被迫再次阻塞,直到另一个消费者从队列。

这是您的实际操作:

  1. 队列的最大大小为 3,从没有元素开始
  2. 从生产者那里得到一些东西,大小还不是 3,阻止wait()而不添加它
  3. 从生产者那里得到一些东西,大小还不是 3,阻止wait()而不添加它
  4. 从生产者那里得到一些东西,大小还不是 3,阻止wait()而不添加它

在添加元素的所有 3 种情况下,元素实际上并没有被添加,我们陷入困境,wait()因为所有 3 种情况都进入了while循环,然后什么都没有调用notifyAll().

您在评论中的修复:

while (q.size() == size)

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

您的代码中不正确的一件事是您在notifyAll添加后调用。添加永远不会导致队列大小缩小,但您会通知putTail方法中等待的所有线程继续。如果您只是将某些内容放入队列中使其达到最大大小,则没有理由通知正在等待将某些内容添加到队列中的线程。我认为您的意思是让该通知对等待最终take方法的线程执行某些操作,这使我想到了下一点:

您的下一步将是拥有两个锁定对象,而不是始终使用this. 这样,该take方法可以与该方法分开阻塞put。使用一个锁waitput方法中并notifyAll在其上take,然后使用另一个锁waittake方法中并notifyAll在其上put。这样您就可以分别通知接受者和推杆者,而无需像使用this.notifyAll.

于 2013-08-10T20:32:17.727 回答
1

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

于 2013-08-10T19:45:23.717 回答
0

问题出在MyQueue类的方法中。putTail()你正在调用(当前对象),它永远不会被通知。然后线程将永远等待。 wait()this

于 2013-08-10T19:46:05.673 回答