I'm trying to utilize the Java PriorityQueue class in the following code:
private static PriorityQueue<String> commandQueue = new PriorityQueue<String>();
private static boolean looping = false;
public static void startCommandHandling() {
new Timer().schedule(new TimerTask() {
@Override
public void run() {
if (!looping) {
while (!commandQueue.isEmpty()) {
looping = true;
String command = commandQueue.poll();
if (Main.communicationPort.isOpen()) {
String string = "!" + command + "\r\n";
byte[] data = string.getBytes();
int dataLength = data.length;
Main.communicationPort.writeBytes(data, dataLength);
}
}
looping = false;
}
}
}, 1, 1);
}
public static void sendCommand(String command) {
commandQueue.add(command);
}
public static void sendCommands(List<String> commands) {
commandQueue.addAll(commands);
}
It's used to queue serial port commands in order to send them one after another. I'm sure that I'm not feeding any null strings to sendCommand() or sendCommands() methods — there is a null check where these methods are called. It sometimes doesn't throw this exception immediately after the task is scheduled and first command(s) are added to the queue, but a lot of the time adding new command(s) will result in NPE and Java application crashing:
Exception in thread "Timer-0" Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main(JarRsrcLoader.java:61)
Caused by: java.lang.NullPointerException
at java.lang.String.compareTo(String.java:1155)
at java.lang.String.compareTo(String.java:111)
at java.util.PriorityQueue.siftUpComparable(PriorityQueue.java:656)
at java.util.PriorityQueue.siftUp(PriorityQueue.java:647)
at java.util.PriorityQueue.offer(PriorityQueue.java:344)
at java.util.PriorityQueue.add(PriorityQueue.java:321)
at java.util.AbstractQueue.addAll(AbstractQueue.java:187)
at com.rpiled.SerialCommands.sendCommands(SerialCommands.java:114)
at com.rpiled.UserSettings.apply(UserSettings.java:31)
at com.rpiled.Main.main(Main.java:32)
... 5 more
java.lang.NullPointerException
at java.util.PriorityQueue.siftDownComparable(PriorityQueue.java:701)
at java.util.PriorityQueue.siftDown(PriorityQueue.java:689)
at java.util.PriorityQueue.poll(PriorityQueue.java:595)
at com.rpiled.SerialCommands$1.run(SerialCommands.java:46)
at java.util.TimerThread.mainLoop(Timer.java:555)
at java.util.TimerThread.run(Timer.java:505)
root@raspberrypi:~#
I suspect that it has something to do with the fact that the command polling is done in task called every 1 millisecond, but I need it to be running so often because I need the commands to be sent as fast as possible while still not allowing them to mix with each other - i.e. two commands can't be sent at the same time (that's why the queue system is needed). I've experimented a lot with this code and find out that creating the new PriorityQueue object with the added initialCapacity value of for example 500 (...= new PriorityQueue<String>(500);
) results in no more application crashes and a bit different NPE:
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main(JarRsrcLoader.java:61)
Caused by: java.lang.NullPointerException
at java.lang.String.compareTo(String.java:1155)
at java.lang.String.compareTo(String.java:111)
at java.util.PriorityQueue.siftUpComparable(PriorityQueue.java:656)
at java.util.PriorityQueue.siftUp(PriorityQueue.java:647)
at java.util.PriorityQueue.offer(PriorityQueue.java:344)
at java.util.PriorityQueue.add(PriorityQueue.java:321)
at java.util.AbstractQueue.addAll(AbstractQueue.java:187)
at com.rpiled.SerialCommands.sendCommands(SerialCommands.java:114)
at com.rpiled.UserSettings.apply(UserSettings.java:31)
at com.rpiled.Main.main(Main.java:32)
... 5 more
How can I resolve this? What is causing the NPE?