阻止队列 - 需要更多信息

时间:2009-05-21 13:47:55

标签: java data-structures concurrency queue

这个问题与我之前的一个问题有关..

Previous Post

在那里,阻塞性质被认为是一种优势。

我尝试开发一些简单的代码来演示阻塞性质,但我遇到了困难。我只是尝试制作一个大小为4的BlockingQueue并尝试添加5个元素,最后得到java.lang.IllegalStateException。有人可以给我看一个阻止BlockingQueue的性质的代码示例吗?


public static void main(String[] args) {
    BlockingQueue<String> bq = new LinkedBlockingQueue<String>(4);

    try {
        bq.offer("A");
        bq.offer("B");
        bq.offer("C");
        bq.offer("D");
        bq.offer("E");

        System.out.println("1 = " + bq.take());
        System.out.println("2 = " + bq.take());
        System.out.println("3 = " + bq.take());
        System.out.println("4 = " + bq.take());
        System.out.println("5 = " + bq.take());
        System.out.println("6 = " + bq.take());
    } catch (Exception e) {
        // TODO: handle exception
        e.printStackTrace();
    }
}

我使用了这段代码。在这种情况下,我试图将5个元素放入大小为4的队列中。在这种情况下,应将4个元素(A,B,C,D)添加到队列中。然后我在打印时调用take()方法。当我打电话给 System.out.println("1 = " + bq.take()); 时,不应该自动将“E”插入队列吗?因为它有一个免费插槽?

4 个答案:

答案 0 :(得分:11)

您是使用addoffer还是put添加的?我假设您使用add,因为它是唯一可以抛出IllegalStateException的人;但如果您阅读table,您会看到如果您想要阻止语义,则应使用put(和take删除)。

编辑:您的示例存在一些问题。

首先,我将回答“第一次拨打take()时为什么不插入E?”答案是,当您致电take()时,您已尝试并失败以插入E.一旦空格被释放,则无需插入任何内容。

现在,如果您将offer()更改为put(),则put("E")将永远不会返回。为什么?因为它正在等待其他一些线程从队列中删除一个元素。请记住,BlockingQueues是为多个线程设计的。如果你有一个单线程的应用程序,阻塞是无用的(实际上比无用的更糟糕。)

这是一个改进的例子:

public static void main(String[] args) {
    final BlockingQueue<String> bq = new LinkedBlockingQueue<String>(4);

    Runnable producer = new Runnable() {
        public void run() {
            try {
                bq.put("A");
                bq.put("B");
                bq.put("C");
                bq.put("D");
                bq.put("E");
            } catch (InterruptedException ex) {
                Thread.currentThread().interrupt(); 
            }
        }
    };
    Runnable consumer = new Runnable() {
        public void run() {
            try {
                System.out.println("1 = " + bq.take());
                System.out.println("2 = " + bq.take());
                System.out.println("3 = " + bq.take());
                System.out.println("4 = " + bq.take());
                System.out.println("5 = " + bq.take());
                System.out.println("6 = " + bq.take());
            } catch (InterruptedException ex) {
                Thread.currentThread().interrupt();
            }
        }
    };
    new Thread(producer).start();
    new Thread(consumer).start();
}

现在put("E")调用实际上会成功,因为它现在可以等到消费者线程从队列中删除“A”。最后一个take()仍会无限制地阻塞,因为没有要移除的第六个元素。

答案 1 :(得分:2)

mmyers把我打败了:P(+1)
那应该是你需要的,祝你好运!

注意: put()在您的示例中将失败,因为put()将阻塞,直到空间可用。由于空间永远不可用,程序永远不会继续执行。

====旧答案======

一个BlockingQueue是一个接口,你必须使用其中一个实现类。

“阻止自然”只是声明你可以从你的队列中请求一些东西,如果它是空的,它所在的线程将阻止(等待)直到某些东西被添加到队列中然后继续处理。

ArrayBlockingQueue
DelayQueue
LinkedBlockingQueue
PriorityBlockingQueue
SynchronousQueue

http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/BlockingQueue.html

//your main collection
LinkedBlockingQueue<Integer> lbq = new LinkedBlockingQueue<Integer>();

//Add your values
lbq.put(100);
lbq.put(200);

//take() will actually remove the first value from the collection, 
//or block if no value exists yet.
//you will either have to interrupt the blocking, 
//or insert something into the queue for the program execution to continue

int currVal = 0;
try {
    currVal = lbq.take();
} catch (InterruptedException e) {
    e.printStackTrace();
}

//your main collection LinkedBlockingQueue<Integer> lbq = new LinkedBlockingQueue<Integer>(); //Add your values lbq.put(100); lbq.put(200); //take() will actually remove the first value from the collection, //or block if no value exists yet. //you will either have to interrupt the blocking, //or insert something into the queue for the program execution to continue int currVal = 0; try { currVal = lbq.take(); } catch (InterruptedException e) { e.printStackTrace(); }

答案 2 :(得分:1)

专门回答你的问题:Offer是一个非阻塞商品调用,所以在你发布的一个单线程方法中,对商品的调用('E')只返回false而不修改完整队列。如果您使用了阻塞放('E')调用,它将一直睡眠,直到空间可用。永远在你的简单例子中。您需要从队列中读取一个单独的线程,以便为put完成创建空间。

答案 3 :(得分:0)

您好了解更多信息

 /**
 * Inserts the specified element into this queue if it is possible to do
 * so immediately without violating capacity restrictions, returning
 * {@code true} upon success and throwing an
 * {@code IllegalStateException} if no space is currently available.
 * When using a capacity-restricted queue, it is generally preferable to
 * use {@link #offer(Object) offer}.
 *
 * @param e the element to add
 * @return {@code true} (as specified by {@link Collection#add})
 * @throws IllegalStateException if the element cannot be added at this
 *         time due to capacity restrictions
 * @throws ClassCastException if the class of the specified element
 *         prevents it from being added to this queue
 * @throws NullPointerException if the specified element is null
 * @throws IllegalArgumentException if some property of the specified
 *         element prevents it from being added to this queue
 */
boolean add(E e);

/**
 * Inserts the specified element into this queue if it is possible to do
 * so immediately without violating capacity restrictions, returning
 * {@code true} upon success and {@code false} if no space is currently
 * available.  When using a capacity-restricted queue, this method is
 * generally preferable to {@link #add}, which can fail to insert an
 * element only by throwing an exception.
 *
 * @param e the element to add
 * @return {@code true} if the element was added to this queue, else
 *         {@code false}
 * @throws ClassCastException if the class of the specified element
 *         prevents it from being added to this queue
 * @throws NullPointerException if the specified element is null
 * @throws IllegalArgumentException if some property of the specified
 *         element prevents it from being added to this queue
 */
boolean offer(E e);

/**
 * Inserts the specified element into this queue, waiting if necessary
 * for space to become available.
 *
 * @param e the element to add
 * @throws InterruptedException if interrupted while waiting
 * @throws ClassCastException if the class of the specified element
 *         prevents it from being added to this queue
 * @throws NullPointerException if the specified element is null
 * @throws IllegalArgumentException if some property of the specified
 *         element prevents it from being added to this queue
 */
void put(E e) throws InterruptedException;

/**
 * Inserts the specified element into this queue, waiting up to the
 * specified wait time if necessary for space to become available.
 *
 * @param e the element to add
 * @param timeout how long to wait before giving up, in units of
 *        {@code unit}
 * @param unit a {@code TimeUnit} determining how to interpret the
 *        {@code timeout} parameter
 * @return {@code true} if successful, or {@code false} if
 *         the specified waiting time elapses before space is available
 * @throws InterruptedException if interrupted while waiting
 * @throws ClassCastException if the class of the specified element
 *         prevents it from being added to this queue
 * @throws NullPointerException if the specified element is null
 * @throws IllegalArgumentException if some property of the specified
 *         element prevents it from being added to this queue
 */
boolean offer(E e, long timeout, TimeUnit unit)
    throws InterruptedException;

/**
 * Retrieves and removes the head of this queue, waiting if necessary
 * until an element becomes available.
 *
 * @return the head of this queue
 * @throws InterruptedException if interrupted while waiting
 */
E take() throws InterruptedException;

/**
 * Retrieves and removes the head of this queue, waiting up to the
 * specified wait time if necessary for an element to become available.
 *
 * @param timeout how long to wait before giving up, in units of
 *        {@code unit}
 * @param unit a {@code TimeUnit} determining how to interpret the
 *        {@code timeout} parameter
 * @return the head of this queue, or {@code null} if the
 *         specified waiting time elapses before an element is available
 * @throws InterruptedException if interrupted while waiting
 */
E poll(long timeout, TimeUnit unit)
    throws InterruptedException;