执行列表操作时出现异常
Exception when I do a list operation
我关注class
我正在监控队列。当一条消息入队时,我记录它,当一条消息出队时,我记录它。此代码适用于 75% correct.Sometimes 文件入队太多,但这不是主要问题案例。
现在让我们看一下下面的代码,首先我与队列建立连接,然后在我对队列进行排队时将消息 ID 添加到我的列表中。如果列表大于队列大小(我每次循环时都会计算),则需要进行出队。帮助列表首先复制数组列表并删除它在队列中遇到的所有项目。它没有遇到的项目来自队列,因此它们需要从列表中取出。如果列表不是更大,我会检查该 id 是否已经在列表中,如果不是,我会创建一个新队列。
package queueFeed;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.command.ActiveMQQueue;
import javax.jms.Message;
import javax.jms.QueueBrowser;
import javax.jms.Session;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.logging.Logger;
public class QueueRunner {
private static Logger log = Logger.getLogger(QueueRunner.class.getName());
public void run() throws Exception {
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("admin","admin","tcp://localhost:61616");
javax.jms.Connection connection = factory.createConnection();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
QueueBrowser browser = session.createBrowser(new ActiveMQQueue("KBC"));
List<String> ids = new ArrayList<>();
int queueSize = 0;
int counter = 0;
connection.start();
while(true) {
Enumeration enumeration = browser.getEnumeration();
if(queueSize < ids.size())
{
List<String> checkList = ids;
while(enumeration.hasMoreElements()){
Message message = (Message) enumeration.nextElement();
checkList.remove(message.getJMSMessageID());
counter++;
}
if(checkList.size() > 0 && ids.size() > 0)
for(String notEncountered : checkList) {
ids.remove(notEncountered);
System.out.println("dequeued " + notEncountered);
}
queueSize = counter;
counter = 0;
}
else {
while(enumeration.hasMoreElements()){
counter++;
Message message = (Message) enumeration.nextElement();
String id = message.getJMSMessageID();
if (!ids.contains(id)) {
ids.add(id);
System.out.println("enqueued message" + message.getJMSMessageID());
Thread.sleep(1000);
}
}
queueSize = counter;
counter = 0;
}
}}}
当我出队时出现以下错误:
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859)
at java.util.ArrayList$Itr.next(ArrayList.java:831)
at queueFeed.QueueRunner.run(QueueRunner.java:43)
at dashboard.Main.main(Main.java:34)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)
错误点在第 43 行,也就是 for(String notEncountered : helpList) 行...怎么了?
您无法使用基于范围的循环删除项目。使用迭代器。
Iterator<String> it = ids.iterator();
while(it.hasNext){
if(checkList.contains(it.next()) it.remove();
}
而不是
for(String notEncountered : checkList) {
ids.remove(notEncountered);
System.out.println("dequeued " + notEncountered);
}
如果您想在循环中修改列表,您要么必须
创建一个临时列表,您 运行 超过:
List<Integer> tmpList = copyOf(myList);
for(int n : tmpList){
if(myList.contains(n) && SomethingIsTrue()){
myList.remove(n);
}
}
或者您必须 运行 向后浏览您的列表
for(int i = myList.size()-1; i >= 0; i--){
if(SomethingIsTrue()){
myList.remove(i);
}
}
注意这是伪代码(有一些检查方法等)
运行 遍历 List 并对其进行修改,您可以在删除其他项目时更改其项目的索引。这就是为什么你得到 ConcurrentModificationException
在你的例子中你说:
List<String> checkList = ids;
所以checkList
和ids
是相等的。如果您从 ids
中删除某些内容,但 运行 覆盖 checkList
,您仍然 运行 覆盖同一对象。您必须创建 ids
列表的副本才能获得临时行为。
在普通的 for 循环中,不可能从列表中删除项目。
您需要使用 Iterator 来执行此操作。
你用
替换你的普通 for 循环
if(checkList.size() > 0 && ids.size() > 0)
{
Iterator<String> iterator = checkList.iterator();
while(iterator.hasNext()) {
String messageId = iterator.next();
System.out.println("dequeued message "+ messageId);
iterator.remove();
}
}
这应该可以解决您的问题。
我关注class
我正在监控队列。当一条消息入队时,我记录它,当一条消息出队时,我记录它。此代码适用于 75% correct.Sometimes 文件入队太多,但这不是主要问题案例。
现在让我们看一下下面的代码,首先我与队列建立连接,然后在我对队列进行排队时将消息 ID 添加到我的列表中。如果列表大于队列大小(我每次循环时都会计算),则需要进行出队。帮助列表首先复制数组列表并删除它在队列中遇到的所有项目。它没有遇到的项目来自队列,因此它们需要从列表中取出。如果列表不是更大,我会检查该 id 是否已经在列表中,如果不是,我会创建一个新队列。
package queueFeed;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.command.ActiveMQQueue;
import javax.jms.Message;
import javax.jms.QueueBrowser;
import javax.jms.Session;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.logging.Logger;
public class QueueRunner {
private static Logger log = Logger.getLogger(QueueRunner.class.getName());
public void run() throws Exception {
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("admin","admin","tcp://localhost:61616");
javax.jms.Connection connection = factory.createConnection();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
QueueBrowser browser = session.createBrowser(new ActiveMQQueue("KBC"));
List<String> ids = new ArrayList<>();
int queueSize = 0;
int counter = 0;
connection.start();
while(true) {
Enumeration enumeration = browser.getEnumeration();
if(queueSize < ids.size())
{
List<String> checkList = ids;
while(enumeration.hasMoreElements()){
Message message = (Message) enumeration.nextElement();
checkList.remove(message.getJMSMessageID());
counter++;
}
if(checkList.size() > 0 && ids.size() > 0)
for(String notEncountered : checkList) {
ids.remove(notEncountered);
System.out.println("dequeued " + notEncountered);
}
queueSize = counter;
counter = 0;
}
else {
while(enumeration.hasMoreElements()){
counter++;
Message message = (Message) enumeration.nextElement();
String id = message.getJMSMessageID();
if (!ids.contains(id)) {
ids.add(id);
System.out.println("enqueued message" + message.getJMSMessageID());
Thread.sleep(1000);
}
}
queueSize = counter;
counter = 0;
}
}}}
当我出队时出现以下错误:
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859)
at java.util.ArrayList$Itr.next(ArrayList.java:831)
at queueFeed.QueueRunner.run(QueueRunner.java:43)
at dashboard.Main.main(Main.java:34)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)
错误点在第 43 行,也就是 for(String notEncountered : helpList) 行...怎么了?
您无法使用基于范围的循环删除项目。使用迭代器。
Iterator<String> it = ids.iterator();
while(it.hasNext){
if(checkList.contains(it.next()) it.remove();
}
而不是
for(String notEncountered : checkList) {
ids.remove(notEncountered);
System.out.println("dequeued " + notEncountered);
}
如果您想在循环中修改列表,您要么必须
创建一个临时列表,您 运行 超过:
List<Integer> tmpList = copyOf(myList);
for(int n : tmpList){
if(myList.contains(n) && SomethingIsTrue()){
myList.remove(n);
}
}
或者您必须 运行 向后浏览您的列表
for(int i = myList.size()-1; i >= 0; i--){
if(SomethingIsTrue()){
myList.remove(i);
}
}
注意这是伪代码(有一些检查方法等)
运行 遍历 List 并对其进行修改,您可以在删除其他项目时更改其项目的索引。这就是为什么你得到 ConcurrentModificationException
在你的例子中你说:
List<String> checkList = ids;
所以checkList
和ids
是相等的。如果您从 ids
中删除某些内容,但 运行 覆盖 checkList
,您仍然 运行 覆盖同一对象。您必须创建 ids
列表的副本才能获得临时行为。
在普通的 for 循环中,不可能从列表中删除项目。 您需要使用 Iterator 来执行此操作。
你用
替换你的普通 for 循环if(checkList.size() > 0 && ids.size() > 0)
{
Iterator<String> iterator = checkList.iterator();
while(iterator.hasNext()) {
String messageId = iterator.next();
System.out.println("dequeued message "+ messageId);
iterator.remove();
}
}
这应该可以解决您的问题。