当我试图学习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
或按随机顺序排列
有什么简单的解决方案来解决这个问题吗?谢谢!
发布于 2019-06-10 05:06:54
在你的情况下,问题是
System.out.println(deque.takeLast());
实际上是两条指令,它们并不是原子的。想象一下这样的场景:
所以这完全取决于操作系统将如何管理线程的执行。
在您的例子中,一种可能的解决方案是向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();
}
}
}
};
还要记住关闭线程池,因为现在您的应用程序将永远不会退出。
https://stackoverflow.com/questions/56517718
复制相似问题