Java - BlockingQueue 卡住多线程应用程序

标签 java java-8 concurrency blockingqueue linkedblockingqueue

我正在创建一个包含两个线程的应用程序:其中一个将值写入 LinkedBlockingQueue,另一个正在读取。我正在使用 ScheduledExecutorService 在几秒钟内运行此操作。 问题是我的应用程序在 BlockingQueue 的方法上卡住,我不明白为什么。

这是一个公共(public)资源:

class Res{
    AtomicInteger atomicInteger = new AtomicInteger(0);
    BlockingQueue<String> q = new LinkedBlockingQueue<>();
}

这是阅读器

Semaphore semaphore = new Semaphore(1); /this is for reader does not take two places in thread pool
Runnable reader = ()->{
    try {
        semaphore.acquire();
        System.out.println(res.q.take()+" "+res.atomicInteger.incrementAndGet());
        semaphore.release();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
};

作者:

Runnable writer = ()->{
    res.q.add("hi");
};

完整代码:

class Res{
    AtomicInteger atomicInteger = new AtomicInteger(0);
    BlockingQueue<String> q = new LinkedBlockingQueue<>();
}
public class Main {

    public static void main(String[] args) throws InterruptedException {

        ScheduledExecutorService executorService = Executors.newScheduledThreadPool(2);
        Res res = new Res();
        Semaphore semaphore = new Semaphore(1); //this is for reader does not take two places in thread pool
        Runnable reader = ()->{
            try {
                semaphore.acquire();
                System.out.println(res.q.take()+" "+res.atomicInteger.incrementAndGet());
                semaphore.release();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        };
        Runnable writer = ()->{
            res.q.add("hi");
        };
        Random rnd = new Random();

        for (int i = 0; i < 20; i++) {
            int time = rnd.nextInt(5)+ 2;
            executorService.schedule(writer,time, TimeUnit.SECONDS);
        }
        for (int i = 0; i < 20; i++) {
            int time = rnd.nextInt(5)+ 2;
            executorService.schedule(reader,time, TimeUnit.SECONDS);
        }

        executorService.shutdown();
}

它应该打印二十行“hi [number]”,但在某些行上卡住。 例如,我当前的打印:

hi 1
hi 2
hi 3
hi 4
hi 5

我发现如果我增加线程数newScheduledThreadPool(20)它就会开始工作,但是我怎样才能用两个线程来完成它呢?谢谢!

最佳答案

尽管很明显同时发生了什么,但遵循您的代码有点困难。由于 Executors.newScheduledThreadPool(2);,您最多可以一次运行两个线程。这两个线程都是读取器线程。

因此Thread-1进入了try block 并通过semaphore.acquire();获取了信号量许可,但是队列为空- 因此它会阻塞 res.q.take()。下一个线程 - Thread-2 也是一个读取线程,但它无法获取 permit,因为它已被 Thread-1 占用> 并在 semaphore.acquire(); 上被阻止。由于您没有空间容纳其他线程(您的池在使用这两个线程时被阻止),因此没有编写器会将某些内容放入您的队列中,从而解锁 Thread-1 (因此 res.q.take() 可以工作)。

添加更多工作线程只会延迟问题的发生 - 您最终可能会处于与之前相同的位置。

关于Java - BlockingQueue 卡住多线程应用程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61088676/

相关文章:

c++ - 如何在 Windows 中进行正确的顺序异步消息处理?

Java/hibernate : How can I insert a specific value for a column with autoincrement/@GeneratedValue

java - 如何检查适配器过滤器是否不对应于 ListView 中的任何条目

java - 为什么在java中,如果在命令行编译中main方法main的参数中给出 "*",这被认为是 "a"

java - foreach 在 json 数组上

java - Scala 中 Java 8 Supplier 接口(interface)的等价物

java - 从内置网络摄像头捕获图像

java.lang.LinkageError : loader constraint violation in interface itable initialization 错误

go - 如何在Go中创建共享队列?

c# - C# 中 Concurrency::combinable<T> 的模拟?