我遇到使用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());
}
}
}
}
答案 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());