java - 阻塞队列 - 需要更多信息

标签 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”不应该自动插入到队列中吗?因为它有一个免费插槽?

最佳答案

您添加的是 add , offer , 或 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() 仍然会无限阻塞,因为没有要删除的第六个元素。

关于java - 阻塞队列 - 需要更多信息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/893021/

相关文章:

c++ - 特定名称的结构导出数据

c++ - 如何同步访问 NAS 上文件的两个进程?

java - 在 Wildfly 16 的应用程序中加载 pk12 文件

java - 子类的构造函数

c - 为什么我的归并排序程序会触发段错误?

c# - 如何创建/使用 'Non Generic Queue'

java - 当我们在方法内创建锁(同步块(synchronized block))对象时会发生什么?

java - 在 JVM 内部和跨 JVM 同步共享文件写入

java - 改变图像不透明度

java - 如何使 Java TrayIcon 成为与对话框关联的组件?