使用ConcurrentLinkedQueue的Java线程问题
我对下面的代码片段有问题。它旨在处理添加到事件队列(ConcurrentLinkedQueue)的事件(通过调用processEvent方法提供)。事件被添加到事件队列中,并在run方法中定期处理 一切几乎总是好的。但有时在调用processEvent方法之后,当事件添加到队列中时,运行部分无法看到有新事件 你知道怎么回事吗?除了使用字符串常量作为锁的明显错误之外使用ConcurrentLinkedQueue的Java线程问题,java,multithreading,concurrency,producer-consumer,Java,Multithreading,Concurrency,Producer Consumer,我对下面的代码片段有问题。它旨在处理添加到事件队列(ConcurrentLinkedQueue)的事件(通过调用processEvent方法提供)。事件被添加到事件队列中,并在run方法中定期处理 一切几乎总是好的。但有时在调用processEvent方法之后,当事件添加到队列中时,运行部分无法看到有新事件 你知道怎么回事吗?除了使用字符串常量作为锁的明显错误之外 import java.util.concurrent.ConcurrentLinkedQueue; public class M
import java.util.concurrent.ConcurrentLinkedQueue;
public class MyCommunicator implements Runnable {
private ConcurrentLinkedQueue<MyEvent> eventQueue = null;
private boolean stopped = false;
private String lock = "";
private Thread thread = null;
public MyCommunicator() {
eventQueue = new ConcurrentLinkedQueue<MyEvent>();
}
public void start() {
thread = new Thread(this, "MyCommunicatorThread");
thread.start();
}
public void stop() {
stopped = true;
synchronized (lock) {
lock.notifyAll();
}
eventQueue.clear();
}
public void run() {
while (!stopped) {
try {
MyEvent event = null;
while (!stopped && ((event = eventQueue.peek()) != null)) {
sendEvent(event);
eventQueue.poll();
}
if (!stopped) {
synchronized (lock) {
lock.wait(10000L);
}
}
}
catch (Exception e) {
}
}
}
/**
* START EVENT JOB - ADD A NEW EVENT TO BE PROCESSED
*/
public void processEvent(MyEvent event) {
eventQueue.offer(event);
synchronized (lock) {
lock.notifyAll();
}
}
/**
* END EVENT JOB
*/
private void sendEvent(MyEvent event) {
// do send event job
}
}
import java.util.concurrent.ConcurrentLinkedQueue;
公共类MyCommunicator实现Runnable{
私有ConcurrentLinkedQueue eventQueue=null;
私有布尔停止=false;
私有字符串锁=”;
私有线程线程=null;
公共MyCommunicator(){
eventQueue=新的ConcurrentLinkedQueue();
}
公开作废开始(){
线程=新线程(这是“MyCommunicatorThread”);
thread.start();
}
公共停车场(){
停止=真;
已同步(锁定){
lock.notifyAll();
}
eventQueue.clear();
}
公开募捐{
当(!停止){
试一试{
MyEvent事件=null;
而(!stopped&((event=eventQueue.peek())!=null)){
发送事件(事件);
eventQueue.poll();
}
如果(!停止){
已同步(锁定){
锁定。等待(10000L);
}
}
}
捕获(例外e){
}
}
}
/**
*开始事件作业-添加要处理的新事件
*/
public void processEvent(MyEvent事件){
eventQueue.offer(事件);
已同步(锁定){
lock.notifyAll();
}
}
/**
*结束事件作业
*/
私有void sendEvent(MyEvent事件){
//是否发送事件作业
}
}
为什么要使用锁和通知
改用a,省去你所有的麻烦
在poll()
上有一个超时将完成您尝试执行的所有操作
编辑:关于当前代码 您需要定义“无法看到有新事件”。您的
run()
方法每10秒查看一次队列;如果队列中有什么东西,它会“看到”并将其拉出
- 如果你的意思是“它不会在收到通知后立即看到它,只需10秒”,那么这很容易回答,因为你有一个很容易导致这种情况发生的比赛条件。当该线程在完成检查/处理队列和获取锁之间时,可以向队列中插入一些内容。如果
上没有超时,您将阻塞,直到插入下一个事件。如果在此期间调用了wait()
方法,您将丢失队列中的所有事件。使用stop()
而不是所有不必要的锁定和通知解决了这个问题。这不是一个“简单”的解决方案,它是这个用例和问题的正确解决方案LinkedBlockingQueue
- 如果不是这样,那么您只是没有向队列中插入任何内容,问题在于您没有在此处发布的代码。在不了解该代码的情况下,猜测您正在尝试在
处插入nulleventQueue.offer(event)
。既然你没有尝试/抓住MyEvent
,你就不会知道。忽略所有异常和不检查返回值都不是一个好主意或做法offer()
- 第三种可能是,您在某个地方有一些其他代码锁定在相同的内部字符串文字引用上,这将导致此代码挂起。你提到了这一点,但我在这里重申——这是一件非常糟糕的事情,特别是考虑到它是空字符串。如果您坚持在这里使用,
包提供了real。请注意,这仍然不会消除您有时错过10秒比赛的情况,但至少会更干净。为了消除竞争条件,您需要放弃并发队列而使用常规队列,只需在访问它之前获取锁(以及获取插入锁)。这将同步您的线程,因为插入器将被阻止插入,除非该线程正在等待锁定条件。在同一块代码中混合使用锁和无锁的线程同步方法通常会导致这些问题java.util.concurrent
poll()
上有一个超时将完成您尝试执行的所有操作
编辑:关于当前代码 您需要定义“无法看到有新事件”。您的
run()
方法每10秒查看一次队列;如果队列中有什么东西,它会“看到”并将其拉出
- 如果你的意思是“它不会在收到通知后立即看到它,只需10秒”,那么这很容易回答,因为你有一个很容易导致这种情况发生的比赛条件。当该线程在完成检查/处理队列和获取锁之间时,可以向队列中插入一些内容。如果
上没有超时,您将阻塞,直到插入下一个事件。如果在此期间调用了wait()
方法,您将丢失队列中的所有事件。使用stop()
而不是所有不必要的锁定和通知解决了这个问题。这不是一个“简单”的解决方案,它是这个用例和问题的正确解决方案LinkedBlockingQueue
- 如果不是这样,那么您只是没有向队列中插入任何内容,问题在于您没有在此处发布的代码。一个对代码一无所知的猜测
catch (Exception e) { }