0
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)
at java.util.TreeMap$EntryIterator.next(TreeMap.java:1136)
at java.util.TreeMap$EntryIterator.next(TreeMap.java:1131)
at java.util.TreeMap.writeObject(TreeMap.java:2250)

为什么?尤其是在我清理地图的时候。如果我只给出一个命令行参数,我不会得到这个例外。但是,如果一遍又一遍地遵守,我会得到同样的例外。
其次,我注意到,当收到消息对象时,它们被存储到 TreeMap 并序列化并返回。当我希望树形图将消息存储一分钟然后序列化整个消息时。

4

5 回答 5

3

java.util.concurrent.ConcurrentSkipListMap是线程安全的实现,TreeMap它将保持自然顺序

Map<String, String> treeMap = new ConcurrentSkipListMap<String, String>();

我们也可以获得不可修改的(只读)版本,如下所示:

TreeMap tM = new TreeMap();
Map tM2 = Collections.unmodifiableMap(tm1);

现在地图tM2是只读的。

于 2014-08-13T16:09:47.800 回答
2

其他答案很接近,但我不相信它们是完整的。如果您查看被抛出的 CME,它位于 TreeMap 迭代器中,即使您将其设为同步映射,也不会使其成为线程安全的。您仍然必须在迭代期间在 TreeMap 上显式同步(在这种情况下,似乎是序列化)。

解释使用迭代器时集合的同步?

于 2012-04-05T09:32:46.780 回答
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;
}
于 2012-08-02T15:56:24.637 回答
0

派对有点晚了,但正如@Flinbor 指出的那样,ConcurrentSkipListMap在这种情况下仍然是要走的路。它仍然是自然排序的或通过 Comparator 排序的,并且对于 theConcurrentSkipListMap和-O TreeMap( log(n))的访问和修改时间是相同的。但是,由于同步,可能会慢一些。

虽然 TreeMap 的 Iterator 是fail-fast,这意味着在迭代创建后有一个结构修改,而不是他自己的remove()方法。虽然 ConcurrentSkipListMap 的 Iterator 是弱一致的,但返回的元素反映了在迭代器创建时或之后的某个时刻映射的状态。它们不会抛出 ConcurrentModificationException。

于 2017-07-19T21:08:09.980 回答
-1

尝试使用Collections

    public static Map <Long,Message> map1 = 
Collections.synchronizedMap(new TreeMap<Long,Message>());

同步您的地图实例。

于 2012-04-05T08:20:54.240 回答