Reputation: 18863
for (final ArrayList<SmartPhone> smartPhones : smartPhonesCluster) {
new Thread(new Runnable() {
@Override
public void run() {
for (SmartPhone smartPhone : smartPhones) {
Queue<SmartPhoneTask> tasks = smartPhone.getSystem()
.getTaskQue();
SmartPhoneTask task = null;
assert tasks != null;
try {
while (!tasks.isEmpty()) {
task = tasks.poll(); // This is the line throwing the exception (GlobalNetwork.java:118)
assert task != null;
task.execute();
task.onTaskComplete();
}
} catch (RuntimeException e) {
e.printStackTrace();
}
}
}
}).start();
}
And log:
java.util.NoSuchElementException
at java.util.LinkedList.remove(LinkedList.java:788)
at java.util.LinkedList.removeFirst(LinkedList.java:134)
at java.util.LinkedList.poll(LinkedList.java:470)
at com.wtsang02.reu.botnet.network.GlobalNetwork$1.run(GlobalNetwork.java:118)
at java.lang.Thread.run(Thread.java:662)
java.lang.NullPointerException
Exception in thread "Thread-299" java.lang.AssertionError
at com.wtsang02.reu.botnet.network.GlobalNetwork$1.run(GlobalNetwork.java:119)
at java.lang.Thread.run(Thread.java:662)
line 118 points to:
task=tasks.poll();
How to solve this? Queue is LinkedList implemenation if that makes a difference.
Upvotes: 5
Views: 6734
Reputation: 43391
LinkedList
is not thread-safe, so you need external synchronization if you access a Linkedlist
on more than one thread. This synchronization is on some object (a synchronized
method is just shorthand for "synchronize on this
"), and both the gets and the puts must be synchronized on the same object. You're definitely doing that here, since you create a new thread for each SmartPhone
, and then access that phone's LinkedList
from there.
If one thread puts into the list while synchronized on someObject1
, and then another thread reads that list while synchronized on someObject2
, then this does not count as external synchronization -- the code is still broken.
Even if you used a thread-safe collection, it'd be possible to hit this exception if multiple threads are emptying the queue at the same time. For instance, imagine this:
thread A: put e into queue1
thread B: queue1.isEmpty()? No, so go on
thread C: queue1.isEmpty()? No, so go on
thread B: queue1.poll() // works
thread C: queue1.poll() // NoSuchElementException
You should use BlockingQueue
, whose poll()
method will return null
if there are no more elements in the list. Keep pulling until you get a null
, and then break the loop.
Upvotes: 10