gpt4 book ai didi

java - ConcurrentModificationException 定时器任务

转载 作者:塔克拉玛干 更新时间:2023-11-02 19:26:42 25 4
gpt4 key购买 nike

当我在取消第一个计时器后启动第二个计时器时,我得到 ConcurrentModificationException。两个计时器都使用单独的 ArrayList 并遍历它。没有对列表进行删除/修改,仍然抛出 ConcurrentModificationException

当我停止第一个计时器并立即启动第二个时,就会发生这种情况。如果我在启动第二个计时器之前等待几秒钟,那么它工作正常。

我最终在两个计时器上制作了传入列表的副本,将副本传递给计时器,但我仍然收到错误。不确定为什么,因为我正在遍历列表并仅读取值。

定时器 #1 的代码:

private void timerwork(final List<Object> list) throws IOException {
timer = new Timer();
final List<Object> taskList = list;
timer.scheduleAtFixedRate(new CustomTimerTask(taskList) {
@Override
public void run() {
if (taskList != null && !taskList.isEmpty()) {
synchronized (taskList) {
for (Object o: taskList) {
try {
// this method takes each object,
// does some logic and writes to a flat file,
// it does not modify the object itself,
// but just reads it and does some calculation
// on some local variables
valueIncrementOperation(o);
} catch (IOException e) {
timer.cancel();
timer.purge();
throw new RuntimeException(e.getMessage(), e);
}
}
//once exited out of the loop, it copies the flat file to another file
try {
copyFileUsingFileChannels(source, finaldest);
} catch (IOException ignore) {
}
}
}

public synchronized void valueIncrementOperation(Object o) throws IOException {
DataInputStream d = new DataInputStream(new FileInputStream(sourcefile));
DataOutputStream out = new DataOutputStream(new FileOutputStream(tempfile));

initialValue = Long.parseLong(o.getDefaullt_value());
String count;
String t;
while ((count = d.readLine()) != null) {
String u = count.toUpperCase();
String[] z = u.split(" ");

if (z[0].contains(o.getO())) {
// .............. *snip* ..............
out.writeBytes(t + "\n");
}
d.close();
out.close();
copyFileUsingFileChannels(source, initialDest);
}

CustomTimerTask 代码:

public class CustomTimerTask extends TimerTask {
private List<Object> list = new ArrayList<Object>();

public CustomTimerTask(List<Object> list) {
this.list = list;
}

@Override
public void run() {
// TODO Auto-generated method stub
}
}

计时器 2 具有类似的逻辑:即,它在传递给计时器 2 之前复制传入列表。

我仍然收到此错误:

Exception in thread "Timer-0" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859)
at java.util.ArrayList$Itr.next(ArrayList.java:831)
at java.util.TimerThread.mainLoop(Timer.java:555)
at java.util.TimerThread.run(Timer.java:505)

解决方法是在启动 timer2 之前等待几秒钟。有没有更好的方法来解决这种情况?

最佳答案

我们从堆栈跟踪中知道异常是从 ArrayList 内部抛出的。因此,让我们看一下处理 List 的代码行。 (为便于阅读,删除了多余的代码)

首先是方法调用:

private void timerwork(final List<Object> list) {
final List<Object> taskList = list;

这意味着 taskList 与传入的对象(称为 list)完全相同

其次,此 List 被传递到 CustomTimerTask 的构造函数中。

timer.scheduleAtFixedRate(new CustomTimerTask(taskList) {

第三,让我们检查一下构造函数:

private List<Object> list = new ArrayList<Object>();
public CustomTimerTask(List<Object> list) {
this.list = list;
}

所以你的 new ArrayList 被扔掉了,取而代之的是参数 list,我们知道它是完全相同的对象传递给 timerwork()

我知道你说:

I ended up making a copy of the incoming list

但这在您发布的任何代码中都看不到。此外,我们不知道(因为您尚未发布)timerwork() 的调用代码,但可能它是这样的:

List<Object> list = ....
timerwork(list);
timerwork2(list);

如果是这样,那么我们会看到两个计时器任务在不同线程中对完全相同的对象 进行操作,这将解释 ConcurrentModificationException

CustomTimerTask 的构造函数中,即使我的诊断不正确,一个简单的修复也是一个好的做法:

private List<Object> list;
public CustomTimerTask(List<Object> list) {
// CustomTimerTask gets its own copy to play with
this.list = new ArrayList<Object>(list);
}

关于java - ConcurrentModificationException 定时器任务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20291241/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com