Java BlockingQueue似乎在传输过程中损坏了数据

时间:2015-05-18 20:17:09

标签: java multithreading corruption blockingqueue

我有 n 生产者线程通过BlockingQueue提供1个消费者线程。我正在使用.put和.take(后者是.peek!= null)。这对于至少十几条消息很有效,除了可变数据损坏,显然是在传输过程中。目前我只是实例化一个生产者线程。

例如,生产者线程将标识一个矩形并设置对象值,然后通过该对象的get的调试行显示它们。腐败前设置值的示例;

22:13:36.797 [Thread-1] DEBUG a.i.AdvancedVideoAnalytics - ROI = {574, 88, 42x110}

然后消费者。获取消息,这里是以与前一个线程完全相同的方式提取的值的调试行。显示了“损坏的”值集的示例;

22:13:36.887 [Thread-0] DEBUG a.i.AwarenessAnalytics - ROI = {574, -1, 42x89}

相关的生产者代码;

FrameWithMotionDetection frameWithMotionDetection;
private final BlockingQueue<FrameWithMotionDetection> queue;
... 
frameWithMotionDetection = new FrameWithMotionDetection();
frameWithMotionDetection.setMotionData(contourAnalysisResults);
frameWithMotionDetection.setCurrentFrame(frameToExamine);
frameWithMotionDetection.setCamera(camera);
logger.debug("FrameWithMotionDetection.CameraID = {}", frameWithMotionDetection.getCamera().getCameraId());
System.out.println("Preparing to send message to AwarenessAnalytics thread");
try {
    queue.put(frameWithMotionDetection);
    }catch (InterruptedException ex) { 
       System.out.println("Exception in queue.put: " + ex );
    }

主应用程序线程产生消费者线程;

FrameWithMotionDetection frameWithMotionDetection = new FrameWithMotionDetection();
BlockingQueue<FrameWithMotionDetection> q = new ArrayBlockingQueue<FrameWithMotionDetection>(1024);
AwarenessAnalytics awarenessAnalytic = new AwarenessAnalytics(q);

相关的消费者代码;

public AwarenessAnalytics(BlockingQueue<FrameWithMotionDetection> q) {
          this.queue = q;
}
...
FrameWithMotionDetection frameWithMotionDetection;
private final BlockingQueue<FrameWithMotionDetection> queue;
...
while (queue.peek() != null){
    frameWithMotionDetection = new FrameWithMotionDetection();
    try {

        frameWithMotionDetection = queue.take();
        frameWithMotionDetectionFromQueue.add(frameWithMotionDetection);
        framesToEvaluate = true;
        }catch (InterruptedException ex) { 
           logger.error("Exception in queue.take: {}", ex );
        }

    logger.debug("FrameMsg received");
    }

生产者线程(AdvancedVideoAnalytics)由使用者线程生成;

tempIntermediateVA = new AdvancedVideoAnalytics(queue);

鉴于大多数数据传输的成功性,BlockingQueue是潜在的问题还是应该在其他地方寻找?

更新:

在通过BlockingQueue发送之前,我正在努力完成某些变量。这需要一个定义为;

的构造函数
public FrameWithMotionDetection(
    ContourAnalysisResults motionData,
    Mat currentFrame,
    Camera camera) {
    this.motionData = motionData;
    this.currentFrame = currentFrame;
    this.camera = camera;
}

现在我正在努力定义一个允许我简单地从queue.take调用实例化对象的构造函数;

frameWithMotionDetection = new FrameWithMotionDetection(queue.take());

或者这是错误的方法吗?

更新2:在.take()之后直接插入调试语句,很明显问题不是BlockingQueue,因此将检查其他方面。感谢大家的帮助。

更新3:事实证明,我传递的复杂对象没有被实例化为消费者中的新对象。我以为我创建了一个新实例,甚至在对象final中创建了一些变量。一旦我退出重置并重新使用我的生产者线程中的复杂对象(现在每次都创建一个新对象),问题就消失了。有几个人非常乐于助人,给@markspace特别提示。

2 个答案:

答案 0 :(得分:2)

如果没有所有代码,很难确切地说出问题所在。但基于你给我们的东西,你正在为所有线程使用共享的FrameWithMotionDetection对象。

如果您定义的FrameWithMotionDetectionBlockingQueue的级别和范围相同,那么您做错了。

在方法中定义FrameWithMotionDetection,不要让它逃脱该方法。

这肯定与BlockingQueue无关。

答案 1 :(得分:2)

  1. 我建议重写FrameWithMotionDetection以便在构造函数中设置所有属性并且也是最终的 - 不可变数据比多线程环境中的可变数据更不容易出现损坏

    < / LI>
  2. 调用peek然后take具有潜在的危险性,因为队列可能在两个方法调用之间被清空(导致消费者无限期挂起)。更安全的替代方案是poll超时,或者take,然后调用以在生产者完成时中断消费者