2012-04-05 95 views
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方法。這兩個類,實例化和運行,有多個參數的時候,給我一個例外TreeMap中的java.util.ConcurrentModificationException

java.util.ConcurrentModificationException 在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) at java.util.TreeMap.writeObject(TreeMap.java:2250)

爲什麼?特別是,當我清除地圖時。如果我只給出一個命令行參數,我不會得到這個例外。但是如果一遍又一遍地進行編輯,我會得到同樣的例外。其次,我注意到,在收到消息對象時,它們被存儲到TreeMap中並被序列化並返回。當我想要樹形圖存儲消息一分鐘,然後序列化整個批次。

+0

你看過http://docs.oracle.com/javase/6/docs/api/java/util/ConcurrentModificationException.html? – claesv 2012-04-05 08:19:30

回答

-1

嘗試使用Collections

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

你的地圖實例同步。

+3

這顯然是錯誤的答案,因爲Collections.synchronizedMap()不能保護ConcurrentModificationException。 – yurgis 2015-08-31 19:55:50

2

其他答案很接近,但我不認爲它們是完整的。如果你看CME被拋出,它在一個TreeMap迭代器中,即使你使它成爲一個synchronizedMap,它也不會成爲線程安全的。在迭代期間,你仍然必須在TreeMap上顯式同步(在這種情況下,序列化看起來)。

Explain synchronization of collections when iterators are used?

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; 
} 
2

java.util.concurrent.ConcurrentSkipListMap是線程安全TreeMap執行,它會保持自然順序

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

我們也獲得不可修改(只讀)版本如下:

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

現在,地圖tM2是隻讀的。

0

一個遲到的黨,但仍位,

爲@Flinbor指出,ConcurrentSkipListMap就是在這樣的情況下要走的路。它仍然是自然或通過比較器訂購的,並且訪問和修改時間對於ConcurrentSkipListMapTreeMap - O(log(n))都是相同的。但是,由於同步可能會稍慢。

雖然TreeMap中的迭代是快速失敗,這意味着有一個結構上的修改後的迭代產生其他比他自己remove()方法。 While ConcurrentSkipListMap的迭代器是

弱一致性,返回的元素反映了迭代器創建時或創建迭代器某一時刻的映射狀態。他們不會拋出ConcurrentModificationException。

相關問題