Java NoSuchElementException 异常
Java NoSuchElementException odity
我们遇到了这个异常,考虑到我们的代码,这似乎是不可能的...
我们将项目添加到静态链表中,然后启动一个线程来处理添加到这些列表中的项目。如果在将项目添加到列表时静态线程已死或为空,我们将再次启动它。一旦处理完所有项目,该线程就会使自己为空。
请参阅下面的小片段
代码:
public class LiveKPIUpdates extends Thread {
private static final int MAX_QUEUE_SIZE = 1000;
private static LinkedList < UpdateLine > highQueue = new LinkedList < UpdateLine > ();
private static LinkedList < UpdateLine > lowQueue = new LinkedList < UpdateLine > ();
private static UpdateThread updateThread = null;
/**
* Thread to process live update queues.
* High priority items are processed first.
*/
static class UpdateThread extends Thread {
@Override
public void run() {
while (!highQueue.isEmpty() || !lowQueue.isEmpty()) {
UpdateLine update = !highQueue.isEmpty() ? highQueue.removeFirst() : lowQueue.removeFirst(); // <<<<< !!! EXCEPTION HAPPENS HERE... Why/How? !!! >>>>>>>>>>>>>>>
//Do stuff with update
}
updateThread = null;
}
}
/**
* Adds the live update to a queue to be processed.
* If the queue is full, the update may be ignored.
*
* @param appender The machine who sent these lines
* @param lines The lines the machine sent. (Can be tray file or machine log lines)
*/
synchronized public static void updateKPIWithMachineLines(AppenderID appender,
String fileName, Date fileDate, LinkedList < String > lines) throws ParseException, SQLException {
for (String line: lines) {
if (line.startsWith("something...")) {
if (highQueue.size() < MAX_QUEUE_SIZE) {
highQueue.add(new UpdateLine(appender, fileName, fileDate, line));
} else {
TLSystemAction.log("Live updates high priority queue full", appender);
}
} else {
if (lowQueue.size() < MAX_QUEUE_SIZE) {
lowQueue.add(new UpdateLine(appender, fileName, fileDate, line));
} else {
TLSystemAction.log("Live updates low priority queue full", appender);
}
}
}
if (updateThread == null) {
updateThread = new UpdateThread();
updateThread.start();
} else if (!updateThread.isAlive()) {
updateThread.interrupt();
updateThread = new UpdateThread();
updateThread.start();
}
}
异常:
[#|2015-03-12T11:12:10.614+1300|SEVERE|glassfish3.0.1|javax.enterprise.system.std.com.sun.enterprise.v3.services.impl|_ThreadID=617736;_ThreadName=Thread-1;|java.util.NoSuchElementException
at java.util.LinkedList.remove(LinkedList.java:788)
at java.util.LinkedList.removeFirst(LinkedList.java:134)
at api.tl.put.LiveKPIUpdates$UpdateThread.run(LiveKPIUpdates.java:67)
编辑: 我更感兴趣的是如果 lowQueue 为空,它是如何到达 lowQueue.removeFirst() 的。逻辑似乎可以避免这种情况。
改变这个
while (!highQueue.isEmpty() || !lowQueue.isEmpty()) {
UpdateLine update = !highQueue.isEmpty() ? highQueue.removeFirst() : lowQueue.removeFirst(); // <<<<< !!! EXCEPTION HAPPENS HERE... Why/How? !!! >>>>>>>>>>>>>>>
//Do stuff with update
}
至此
while (!highQueue.isEmpty() || !lowQueue.isEmpty()) {
UpdateLine update = !highQueue.isEmpty() ? highQueue.removeFirst() : (!lowQueue.isEmpty() : lowQueue.removeFirst() ? [something else that you know]); // <<<<< !!! EXCEPTION HAPPENS HERE... Why/How? !!! >>>>>>>>>>>>>>>
//Do stuff with update
}
基本上,根据您调用 lowQueue.removeFirst() 的代码,您的 lowQueue 可以为空,因为 ||如果第一个条件为真,则 while() 中的运算符通过,并且在这种情况下它不检查第二个条件,因为它是一个或操作。
你可以查看这个
Does Java evaluate remaining conditions after boolean result is known?
或这个
如果您在代码中列出空条件,那么看起来不可能出现这种异常。看起来 @muasif80 的回答也可能会解决它。但是,由于竞争条件,您的代码中可能会出现意外行为。您只看到一种问题;在现实生活中,您可能会看到更多此类意外和无法解释的故障。 java.util.LinkedList
不是线程安全的 class。当您在多个线程之间共享线程不安全 class 的实例时,您会看到这种意想不到的行为。同步列表访问,您应该可以毫无问题地看到代码 运行。由于您有多个列表,因此您应该在一个公共对象上进行同步。
public class LiveKPIUpdates extends Thread {
private static final int MAX_QUEUE_SIZE = 1000;
private static LinkedList < UpdateLine > highQueue = new LinkedList < UpdateLine > ();
private static LinkedList < UpdateLine > lowQueue = new LinkedList < UpdateLine > ();
private static UpdateThread updateThread = null;
private static Object lock = new Object();
/**
* Thread to process live update queues.
* High priority items are processed first.
*/
static class UpdateThread extends Thread {
@Override
public void run() {
boolean queueHasData = false;
synchronized(lock) {
queueHasData = !highQueue.isEmpty() || !lowQueue.isEmpty();
}
while (queueHasData) {
UpdateLine update;
synchronized(lock) {
update = !highQueue.isEmpty() ? highQueue.removeFirst() : lowQueue.removeFirst();
queueHasData = !highQueue.isEmpty() || !lowQueue.isEmpty();
}
//Do stuff with update
}
updateThread = null;
}
}
/**
* Adds the live update to a queue to be processed.
* If the queue is full, the update may be ignored.
*
* @param appender The machine who sent these lines
* @param lines The lines the machine sent. (Can be tray file or machine log lines)
*/
synchronized public static void updateKPIWithMachineLines(AppenderID appender,
String fileName, Date fileDate, LinkedList < String > lines) throws ParseException, SQLException {
for (String line: lines) {
if (line.startsWith("something...")) {
synchronized(lock) {
if (highQueue.size() < MAX_QUEUE_SIZE) {
highQueue.add(new UpdateLine(appender, fileName, fileDate, line));
} else {
TLSystemAction.log("Live updates high priority queue full", appender);
}
}
} else {
synchronized(lock) {
if (lowQueue.size() < MAX_QUEUE_SIZE) {
lowQueue.add(new UpdateLine(appender, fileName, fileDate, line));
} else {
TLSystemAction.log("Live updates low priority queue full", appender);
}
}
}
}
if (updateThread == null) {
updateThread = new UpdateThread();
updateThread.start();
} else if (!updateThread.isAlive()) {
updateThread.interrupt();
updateThread = new UpdateThread();
updateThread.start();
}
}
虽然此代码在同步访问列表后可能会按预期工作,但这不是最佳解决方案。这是一个 class 典型的生产者-消费者问题。 Java 具有用于处理生产者消费者问题的等待...通知机制。您可以在网络上获得许多生产者消费者的示例。阅读、学习并实施等待...通知模式。
我们遇到了这个异常,考虑到我们的代码,这似乎是不可能的... 我们将项目添加到静态链表中,然后启动一个线程来处理添加到这些列表中的项目。如果在将项目添加到列表时静态线程已死或为空,我们将再次启动它。一旦处理完所有项目,该线程就会使自己为空。
请参阅下面的小片段
代码:
public class LiveKPIUpdates extends Thread {
private static final int MAX_QUEUE_SIZE = 1000;
private static LinkedList < UpdateLine > highQueue = new LinkedList < UpdateLine > ();
private static LinkedList < UpdateLine > lowQueue = new LinkedList < UpdateLine > ();
private static UpdateThread updateThread = null;
/**
* Thread to process live update queues.
* High priority items are processed first.
*/
static class UpdateThread extends Thread {
@Override
public void run() {
while (!highQueue.isEmpty() || !lowQueue.isEmpty()) {
UpdateLine update = !highQueue.isEmpty() ? highQueue.removeFirst() : lowQueue.removeFirst(); // <<<<< !!! EXCEPTION HAPPENS HERE... Why/How? !!! >>>>>>>>>>>>>>>
//Do stuff with update
}
updateThread = null;
}
}
/**
* Adds the live update to a queue to be processed.
* If the queue is full, the update may be ignored.
*
* @param appender The machine who sent these lines
* @param lines The lines the machine sent. (Can be tray file or machine log lines)
*/
synchronized public static void updateKPIWithMachineLines(AppenderID appender,
String fileName, Date fileDate, LinkedList < String > lines) throws ParseException, SQLException {
for (String line: lines) {
if (line.startsWith("something...")) {
if (highQueue.size() < MAX_QUEUE_SIZE) {
highQueue.add(new UpdateLine(appender, fileName, fileDate, line));
} else {
TLSystemAction.log("Live updates high priority queue full", appender);
}
} else {
if (lowQueue.size() < MAX_QUEUE_SIZE) {
lowQueue.add(new UpdateLine(appender, fileName, fileDate, line));
} else {
TLSystemAction.log("Live updates low priority queue full", appender);
}
}
}
if (updateThread == null) {
updateThread = new UpdateThread();
updateThread.start();
} else if (!updateThread.isAlive()) {
updateThread.interrupt();
updateThread = new UpdateThread();
updateThread.start();
}
}
异常:
[#|2015-03-12T11:12:10.614+1300|SEVERE|glassfish3.0.1|javax.enterprise.system.std.com.sun.enterprise.v3.services.impl|_ThreadID=617736;_ThreadName=Thread-1;|java.util.NoSuchElementException
at java.util.LinkedList.remove(LinkedList.java:788)
at java.util.LinkedList.removeFirst(LinkedList.java:134)
at api.tl.put.LiveKPIUpdates$UpdateThread.run(LiveKPIUpdates.java:67)
编辑: 我更感兴趣的是如果 lowQueue 为空,它是如何到达 lowQueue.removeFirst() 的。逻辑似乎可以避免这种情况。
改变这个
while (!highQueue.isEmpty() || !lowQueue.isEmpty()) {
UpdateLine update = !highQueue.isEmpty() ? highQueue.removeFirst() : lowQueue.removeFirst(); // <<<<< !!! EXCEPTION HAPPENS HERE... Why/How? !!! >>>>>>>>>>>>>>>
//Do stuff with update
}
至此
while (!highQueue.isEmpty() || !lowQueue.isEmpty()) {
UpdateLine update = !highQueue.isEmpty() ? highQueue.removeFirst() : (!lowQueue.isEmpty() : lowQueue.removeFirst() ? [something else that you know]); // <<<<< !!! EXCEPTION HAPPENS HERE... Why/How? !!! >>>>>>>>>>>>>>>
//Do stuff with update
}
基本上,根据您调用 lowQueue.removeFirst() 的代码,您的 lowQueue 可以为空,因为 ||如果第一个条件为真,则 while() 中的运算符通过,并且在这种情况下它不检查第二个条件,因为它是一个或操作。
你可以查看这个
Does Java evaluate remaining conditions after boolean result is known?
或这个
如果您在代码中列出空条件,那么看起来不可能出现这种异常。看起来 @muasif80 的回答也可能会解决它。但是,由于竞争条件,您的代码中可能会出现意外行为。您只看到一种问题;在现实生活中,您可能会看到更多此类意外和无法解释的故障。 java.util.LinkedList
不是线程安全的 class。当您在多个线程之间共享线程不安全 class 的实例时,您会看到这种意想不到的行为。同步列表访问,您应该可以毫无问题地看到代码 运行。由于您有多个列表,因此您应该在一个公共对象上进行同步。
public class LiveKPIUpdates extends Thread {
private static final int MAX_QUEUE_SIZE = 1000;
private static LinkedList < UpdateLine > highQueue = new LinkedList < UpdateLine > ();
private static LinkedList < UpdateLine > lowQueue = new LinkedList < UpdateLine > ();
private static UpdateThread updateThread = null;
private static Object lock = new Object();
/**
* Thread to process live update queues.
* High priority items are processed first.
*/
static class UpdateThread extends Thread {
@Override
public void run() {
boolean queueHasData = false;
synchronized(lock) {
queueHasData = !highQueue.isEmpty() || !lowQueue.isEmpty();
}
while (queueHasData) {
UpdateLine update;
synchronized(lock) {
update = !highQueue.isEmpty() ? highQueue.removeFirst() : lowQueue.removeFirst();
queueHasData = !highQueue.isEmpty() || !lowQueue.isEmpty();
}
//Do stuff with update
}
updateThread = null;
}
}
/**
* Adds the live update to a queue to be processed.
* If the queue is full, the update may be ignored.
*
* @param appender The machine who sent these lines
* @param lines The lines the machine sent. (Can be tray file or machine log lines)
*/
synchronized public static void updateKPIWithMachineLines(AppenderID appender,
String fileName, Date fileDate, LinkedList < String > lines) throws ParseException, SQLException {
for (String line: lines) {
if (line.startsWith("something...")) {
synchronized(lock) {
if (highQueue.size() < MAX_QUEUE_SIZE) {
highQueue.add(new UpdateLine(appender, fileName, fileDate, line));
} else {
TLSystemAction.log("Live updates high priority queue full", appender);
}
}
} else {
synchronized(lock) {
if (lowQueue.size() < MAX_QUEUE_SIZE) {
lowQueue.add(new UpdateLine(appender, fileName, fileDate, line));
} else {
TLSystemAction.log("Live updates low priority queue full", appender);
}
}
}
}
if (updateThread == null) {
updateThread = new UpdateThread();
updateThread.start();
} else if (!updateThread.isAlive()) {
updateThread.interrupt();
updateThread = new UpdateThread();
updateThread.start();
}
}
虽然此代码在同步访问列表后可能会按预期工作,但这不是最佳解决方案。这是一个 class 典型的生产者-消费者问题。 Java 具有用于处理生产者消费者问题的等待...通知机制。您可以在网络上获得许多生产者消费者的示例。阅读、学习并实施等待...通知模式。