使用ConcurrentLinkedQueue的Java线程问题
|
我的以下代码片段有问题。它旨在处理添加到事件队列(ConcurrentLinkedQueue)中的事件(通过对processEvent方法的调用提供)。将事件添加到事件队列中,并在run方法中对其进行定期处理。
几乎总是一切都很好。但是有时在调用processEvent方法之后,将事件添加到队列时,运行部分无法看到有新事件。
有什么问题的主意吗?除了使用String常量作为锁的明显错误之外?
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
}
}
没有找到相关结果
已邀请:
4 个回复
诧不达
。 或者,我们有几个ReusableLatch,例如用于单个读取器线程的BooleanLatch或用于多方支持的PhasedLatch。
扇献隙
方法每10秒查看一次队列;如果队列中有东西,它将“看到”并拉出。 如果您的意思是“收到通知后不会立即看到它,仅10秒后就可以看到”,那么这很容易回答,因为您的比赛条件很容易导致这种情况发生。在此线程介于完成检查/处理队列和获取锁之间的期间,可以在队列中插入某些内容。如果在ѭ6上没有超时,您将阻塞直到插入下一个事件。如果在这段时间内正在调用
方法,则您将丢失队列中的所有事件。使用
代替所有不必要的锁定和通知即可解决此问题。这不是一个“简单”的解决方案,它是针对此用例和问题的正确解决方案。 如果不是这种情况,那么您根本就没有在队列中插入任何内容,问题出在您未在此处发布的代码中。一个不知道该代码的猜测可能是您试图在ѭ10处插入一个空ѭ9。由于您没有尝试/抓住11英镑,因此您不会知道。忽略所有异常而不检查返回的值既不是一个好主意,也不是一种实践。 第三种可能性是,您在其他某个位置上锁定了相同的确切字符串字面量引用,从而导致该代码挂起。您提到了它,但我会在这里重申-这确实是一件坏事,特别是考虑到它是空字符串。如果您坚持在此处使用
软件包,则可以提供带有条件的实锁。请注意,这仍然无法消除您有时会错过10秒比赛的竞争状况,但至少会更加干净。为了消除竞争状况,您希望放弃并发队列的常规队列,并在访问它之前先获取该锁(以及获取插入的锁)。这将使您的线程同步,因为除非该线程正在等待锁定条件,否则将阻止插入该插入器。在同一代码段中混合使用锁和无锁方法来进行线程同步通常会导致这些问题。
磁辫覆氓
捕获任何ѭ14(包括ѭ15及其各种子类)然后忽略它的处理程序通常是一个坏主意。如果这是为了捕获特定类型的异常(例如,可能由
抛出的
),则应将其限制为该异常类型。如果您有捕获任何异常的某种原因,那么至少应在发生异常时记录一些内容。
部窖空