我有以下课程
我在监视一个队列。当一条消息入队时我会记录它,当消息出列时也是如此。这段代码适用于75%的纠正。有时文件会被排队太多,但这不是主要的问题。
现在让我们看看下面的代码,首先我与队列建立连接,而不是在我排队队列时将消息ID添加到我的列表中。如果列表大于队列大小(我每次循环时都计算它),则需要发生出队。帮助列表首先复制arraylist并删除它在队列中遇到的所有项目。它没有遇到的项目来自队列,所以他们需要从列表中出队。如果列表不大,我会检查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)行...出了什么问题?
答案 0 :(得分:1)
如果要在循环中修改List,则必须
创建您运行的临时列表:
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
列表的副本才能获得临时行为。
答案 1 :(得分:0)
您无法使用基于范围的循环删除项目。使用迭代器。
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);
}
答案 2 :(得分:-2)
在正常的for循环中,无法从列表中删除项目。 你需要使用迭代器来进行这种表演。
您可以通过
替换正常的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();
}
}
这可以解决您的问题。