从同步列表中删除元素的正确方法
我有一个客户端 - 服务器样式的设计。我所做的是创建一个名为RequestController
的类,该类控制并监视作为线程对象所做的所有服务器请求。从同步列表中删除元素的正确方法
这些请求线程在同步Map
(使用Collections.synchronizedMap(new HashMap<Long, RequestThread>())
创建)中进行跟踪。每半秒钟检查一次每个请求线程,如果它仍然活着,它会发送一个进度信息给它感兴趣的侦听器对象(请求线程的一个属性),如果它已经完成或失败,它会通知相关的侦听器,并将其本身从同步中移除Map
当其run()
方法完成时。
我用来跟踪每个请求的RequestThread
对象是RequestController
对象的受保护内部类,用于监视所有请求。所以它有权访问包含它的地图。
在这里,我有问题。当从地图中删除“死线”时,我会收到并发修改异常。我对地图的所有访问都是同步的,所以我不明白我如何得到异常。
这里是控制环路的代码:
this.reqTimer = new Timer("Request Timer", true);
TimerTask reqTask = new TimerTask()
{
@Override
public void run()
{
synchronized(reqList)
{
for(RequestThread rt : reqList.values())
rt.updateProgress();
}
}
};
this.reqTimer.scheduleAtFixedRate(reqTask, 500L, 500L);
在RequestThread.run()
方法的结尾处,有呼叫到RequestController
方法本身从地图像这样除去:
public void removeRequest(long id)
{
synchronized(this.reqList)
{
this.reqList.remove(id);
}
}
它看起来如果一个RequestThread.run()
完成,而TimerTask.run()
方法循环调用updateProgress()
方法的请求的映射,则删除不会被阻止,但可以更改映射和c请用我的例外。两个不同线程如何同时锁定同一个对象?不应该删除被阻止,因为它发源于不同的线程,直到更新完成?
我打算把我的意见变成答案。
两个不同线程如何同时获得对同一个对象的锁定?
他们不能。并发修改必须在其他地方。我怀疑你的updateProgress()
是从列表中删除的内容。这可能是并发修改异常发生的地方。
for (RequestThread rt : reqList.values()) {
// you can't make any changes to reqList inside of the loop
rt.updateProgress();
}
如果你需要有updateProgress()
从列表中删除的要求,那么你既可以:
- 使用迭代器并通过迭代器
updateProgress()
所以它可以调用iterator.remove()
。 - 将
List<RequestThread>
传递给updateProgress()
并添加要删除的请求。然后,一旦您位于for循环之外(但仍在同步块中),则可以从reqList
中删除删除列表中的项目。
这与我实际做的最接近。我只是停止从列表中删除线程,并让run()方法结束。我也按照建议切换到了Iterator,每次updateProgress()检查后,看看线程是否还活着 - 如果没有,那么我使用Iterator的线程安全的remove()方法。 – BigMac66 2012-03-19 15:22:49
您也需要后进行清除整个列表迭代: -
synchronized (reqList) {
// Keep track of items to be removed.
List<RequestThread> remove = new LinkedList<RequestThread>();
for (RequestThread rt : reqList.values()) {
rt.updateProgress(remove);
}
// Remove them.
reqList.removeAll(remove);
}
,或者你需要使用一个Iterator
,并使用其remove
方法。
有什么异常? – 2012-02-27 17:02:35
第一个代码片段中的'reqList'和第二个中的'this.reqList'引用同一个对象,对吗?没有足够的代码显示清楚。 – 2012-02-27 20:49:47
Tom Hawtin - ConcurrentModificationException – BigMac66 2012-02-28 14:04:49