首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >多个消费者线程总体上消耗队列FIFO

多个消费者线程总体上消耗队列FIFO
EN

Stack Overflow用户
提问于 2019-06-10 03:22:27
回答 1查看 328关注 0票数 0

当我试图学习JAVA编程的多线程部分时,在处理单生产者-多消费者编码时,我遇到了以下问题。

我试图实现的是:多个使用者线程按照项目被放入队列的顺序将项目从队列中取出。换句话说,使使用者线程总体上保持FIFO方式。

final BlockingDeque<String> deque = new LinkedBlockingDeque<String>();

Runnable rb = new Runnable() {
    public void run() {
        try {
            System.out.println(deque.takeLast());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
};

deque.putFirst("a");
deque.putFirst("b");
deque.putFirst("c");
deque.putFirst("d");

ExecutorService pool = Executors.newFixedThreadPool(4);
pool.submit(rb);
pool.submit(rb);
pool.submit(rb);
pool.submit(rb);

我要找的是:a,b,c,d

它实际输出的内容:b、c、a、d

或按随机顺序排列

有什么简单的解决方案来解决这个问题吗?谢谢!

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-06-10 05:06:54

在你的情况下,问题是

System.out.println(deque.takeLast());

实际上是两条指令,它们并不是原子的。想象一下这样的场景:

  1. 线程1从队列中获取字符串。
  2. 线程2从队列中获取字符串。
  3. 线程2打印值。
  4. 线程1打印值。

所以这完全取决于操作系统将如何管理线程的执行。

在您的例子中,一种可能的解决方案是向run方法添加synchronized关键字:

Runnable rb = new Runnable() {
    public synchronized void run() {
         try {
              String s = deque.takeLast();
              System.out.println(s);
         } catch (InterruptedException e) {
              e.printStackTrace();
         }
    }
};

这将在您在此处创建的匿名类的实例上同步。由于您正在将相同的runnable传递给ExecutorService,因此它应该可以工作。或者你可以在你的queue对象上同步,因为你传递给ExecutorService的runnable会在很多线程中执行,它可以访问队列对象:

Runnable rb = new Runnable() {
    public void run() {
        synchronized (deque) {
             try {
                 String s = deque.takeLast();
                 System.out.println(s);
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }
        }
    }
};

还要记住关闭线程池,因为现在您的应用程序将永远不会退出。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56517718

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档