public class StoreMessage extends Thread implements Serializable{
private static long start_nanotime=System.nanoTime();
private static int timeToRun = 60000;
private static byte[] b=null;
private static long startTime = System.currentTimeMillis();
private static long runUntilMillis = System.currentTimeMillis() + timeToRun;
public static Map <Long,Message> map1=new TreeMap<Long,Message>();
public static void store(Message message)throws Exception{
while (true) {
long now = System.currentTimeMillis();
if (now >= runUntilMillis) {
break;
}
long precise_time=TimeUnit.MILLISECONDS.toNanos(now)+(System.nanoTime()-start_nanotime);
map1.put(precise_time, message);
}
}
public static byte[] returning()throws Exception
{
b=serializer.serialize(map1);
System.out.println(b);
map1.clear();
return b;
}
}
我要做的是,将StoreMessage类每隔一分钟收到的所有消息对象存储到TreeMap中,序列化该TreeMap并将其返回给调用它的类,并为下一个创建/清除TreeMap分钟存储其他消息对象
消息类的消息对象是jms文本消息,它们作为命令行参数输入。 store
方法在另一个类中调用,而returning
方法在另一个类中调用。这两个类在实例化和运行时都有多个参数,给我一个例外
java.util.ConcurrentModificationException at java.util.TreeMap $ PrivateEntryIterator.nextEntry(TreeMap.java:1100) 在java.util.TreeMap $ EntryIterator.next(TreeMap.java:1136) at java.util.TreeMap $ EntryIterator.next(TreeMap.java:1131) 在java.util.TreeMap.writeObject(TreeMap.java:2250)
为什么呢?特别是,当我清理地图时。如果我只给出一个命令行参数,我不会得到这个例外。但如果一遍又一遍地遵守,我会得到同样的例外 其次,我注意到,当消息对象被接收时,它们被存储到TreeMap中并被序列化并返回。当我希望树图存储消息一分钟然后序列化整个批次时。
答案 0 :(得分:2)
其他答案很接近,但我不相信它们是完整的。如果你看一下被抛出的CME,它就在一个TreeMap迭代器中,即使你把它作为一个synchronizedMap也不会成为线程安全的。您仍然必须在迭代期间在TreeMap上显式同步(在这种情况下,似乎是序列化)。
Explain synchronization of collections when iterators are used?
答案 1 :(得分:2)
java.util.concurrent.ConcurrentSkipListMap
是线程安全TreeMap
的实现,它将保持自然顺序
Map<String, String> treeMap = new ConcurrentSkipListMap<String, String>();
我们也可以获得不可修改的(只读)版本,如下所示:
TreeMap tM = new TreeMap();
Map tM2 = Collections.unmodifiableMap(tm1);
现在地图tM2
是只读的。
答案 2 :(得分:0)
理论上,即使使用同步地图,您也可能会丢失消息。如果在System.out.println()
正在进行时调用商店。这是在序列化之后但在它被清除之前。
所以我认为你可以在地图上同步(但我没有测试它):
public static void store(Message message) throws Exception {
while (true) {
long now = System.currentTimeMillis();
if (now >= runUntilMillis) {
break;
}
long precise_time = TimeUnit.MILLISECONDS.toNanos(now)
+ (System.nanoTime() - start_nanotime);
synchronized (map1) {
map1.put(precise_time, message);
}
}
}
public static byte[] returning() throws Exception {
synchronized (map1) {
b = serializer.serialize(map1);
System.out.println(b);
map1.clear();
}
return b;
}
答案 3 :(得分:0)
派对有点迟,但仍然,
正如@Flinbor指出的那样,ConcurrentSkipListMap
是在这种情况下走的路。它仍然是自然地或通过比较器订购的,ConcurrentSkipListMap
和TreeMap
- O(log(n))的访问和修改时间是相同的。但是,由于同步,可能会慢一点。
虽然TreeMap的Iterator是 fail-fast ,但意味着迭代创建后的结构修改不是他自己的 remove()
方法。而ConcurrentSkipListMap的迭代器是
弱一致,返回元素反映迭代器创建时或之后某点的映射状态。它们不会抛出ConcurrentModificationException。
答案 4 :(得分:-1)
尝试使用Collections
:
public static Map <Long,Message> map1 =
Collections.synchronizedMap(new TreeMap<Long,Message>());
同步你的Map实例。