多线程Java代码的空指针异常

时间:2013-11-22 05:00:26

标签: java multithreading nullpointerexception

我遇到使用SimJava仿真库的Java代码问题。该库基本上有助于创建可以作为java线程运行的独立实体。我遇到的问题是我有一个代码段,用作作为线程运行的每个实体的主体。这些实体/线程在这些线程之间共享一个事件(传输ConcurrentLinkedQueue)。我使用concurrentlinkedqueue,因为我遇到了LinkedList并发控制的问题。 问题是,如果我将模型运行100次或更少,它可以正常工作。如果我去100或更多,我得到并发队列的空指针异常。这是有问题的正文的代码段。

空指针异常发生在我试图从队列中拉出的行,即使前面的行检查队列是空还是空。线路上抛出异常 “nextNode = dcPath.poll()。intValue();”

由于某种原因,poll调用返回null,并且intValue()正在应用于null对象。我的问题是,如果if语句之前已经检查了队列内容,这怎么可能?我怎样才能控制这种竞争条件?

public void body() { 
  synchronized (this){
  ConcurrentLinkedQueue<Integer> dcPath = new ConcurrentLinkedQueue<Integer> ();    
  int nextNode;
  int distance = 0;
  while (Sim_system.running()) {
    Sim_event e = new Sim_event();
    sim_get_next(e);    // Get the next event
    dcPath = (ConcurrentLinkedQueue<Integer>) e.get_data();
    if ((dcPath != null) && (!dcPath.isEmpty())){
      nextNode = dcPath.poll().intValue(); // THIS LINE IS THROWING NPE Exception
      if ((dcPath != null) && (!dcPath.isEmpty())){
        int outPort = findMatchingOutPort(dcPath.peek().intValue());
        if (outPort != -1){
          sim_schedule(out[outPort], 0.0, 0, dcPath); 
          distance = this.calculateSensorToSensorDistance (out[outPort].get_dest());
        }                 
      }
    }
  }

2 个答案:

答案 0 :(得分:1)

我认为问题在于,当您从e.get_data()检索dc_path时,另一个线程会同时读/写到该队列中。所以你的代码是:

if ((dcPath != null) && (!dcPath.isEmpty()) {

同时,dcPath不为空。但是当执行下一行时,另一个线程弹出剩余的元素并使队列为空,这就是为什么你得到dcPath.poll()空值。

要防止这种情况发生,您需要同步dcPath引用而不是this。如下:

if (dcPath != null) {
    synchronized (dcPath) {
        //do something
    }
}

此外,在涉及对象的读/写的任何其他线程中,您还需要同步它以确保按预期运行。

答案 1 :(得分:0)

我想出了如何解决这个问题,我不会说这是最有效的方式(特别是在内存管理方面)但它会为我的模拟模型和我需要运行的实例数量做的工作。 我基本上在每个线程实例上创建了ConcurrentLinkedQueue dcPath对象的副本,并在对象时移动。这在操纵物体时消除了竞争条件。我现在可以运行超过一千次迭代,而不会抛出超过500个实例的扩展线程。

if (e.get_data() != null){
       ConcurrentLinkedQueue<Integer> dcPath = new ConcurrentLinkedQueue<Integer>        
                                   ((ConcurrentLinkedQueue<Integer>) e.get_data());