2014-01-06 21 views
1

我創建了一個例子來理解併發HashMap,但它似乎在7-8次運行後給出了不確定的輸出。ConcurrentHashMap在多線程應用中沒有給出正確的輸出

在我的例子中,我創建了三個線程(它們模仿三個服務來獲取數學,科學,英語的分數),它更新了一個只有3個鍵值對的共享HashMap(鍵是三個名字A,B,C並在運行結束時的值應該是三個科目的累積分數)

我發佈了下面的代碼,請注意。

錯誤的輸出如下所示(正確的應該結束等來全部完成主:{C = 27,A = 57,B = 42})

Within run Math : {C=0, A=0, B=0} 
Within run Science : {C=0, A=0, B=0} 
Completed Science : {C=10, A=39, B=29} 
Completed Math : {C=10, A=39, B=29} 
Within run English : {C=0, A=0, B=0} 
Completed English : {C=18, A=57, B=42} 
All Done main : {C=18, A=57, B=42} 

ConcurrentHashMapExample類:

package com.ll.thread.concurrency; 

    import java.util.Iterator; 
    import java.util.concurrent.ConcurrentHashMap; 
    import java.util.concurrent.CountDownLatch; 

    public class ConcurrentHashMapExample { 

     public static void main(String[] args) { 
      // TODO Auto-generated method stub 
      ConcurrentHashMap<String, Integer> concurrentHashMap = new ConcurrentHashMap<String, Integer>(); 
      concurrentHashMap.put("A", 0); 
      concurrentHashMap.put("B", 0); 
      concurrentHashMap.put("C", 0); 
      CountDownLatch countDownLatch = new CountDownLatch(3); 

      Runnable runnableScience = new Worker(concurrentHashMap , "Science" , countDownLatch); 
      Runnable runnableMath = new Worker(concurrentHashMap , "Math" , countDownLatch); 
      Runnable runnableEnglish = new Worker(concurrentHashMap , "English" , countDownLatch); 

      new Thread(runnableScience , "Science").start(); 
      new Thread(runnableMath ,"Math").start(); 
      new Thread(runnableEnglish ,"English").start(); 

      try { 
       countDownLatch.await(); 
      } catch (InterruptedException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 
      System.out.println("All Done " + Thread.currentThread().getName() + " : "+concurrentHashMap); 




      concurrentHashMap = null; 



     } 

    } 

Worker類:​​

package com.ll.thread.concurrency; 

    import java.util.Iterator; 
    import java.util.concurrent.ConcurrentHashMap; 
    import java.util.concurrent.CountDownLatch; 

    public class Worker implements Runnable{ 

     ConcurrentHashMap<String, Integer> concurrentHashMap ; 
     String threadName = ""; 
     CountDownLatch countDownLatch ; 

     public Worker(ConcurrentHashMap<String, Integer> concurrentHashMap, 
       String subject, CountDownLatch countDownLatch) { 
      this.concurrentHashMap = concurrentHashMap; 
      this.threadName = subject ; 
      this.countDownLatch = countDownLatch; 

      // TODO Auto-generated constructor stub 
     } 

     @Override 
     public void run() { 
      // TODO Auto-generated method stub 
      System.out.println("Within run " +Thread.currentThread().getName() + " : "+concurrentHashMap); 
      try{ 
     for(Iterator<String> iterator = concurrentHashMap.keySet().iterator() ; iterator.hasNext();){ 
      String key = iterator.next(); 

      //synchronized (this) { 


      if("Math".equals(Thread.currentThread().getName())) { 
      if("A".equals(key)) 
       concurrentHashMap.put(key, concurrentHashMap.get(key) +20); 
      else if("B".equals(key)) 
       concurrentHashMap.put(key, concurrentHashMap.get(key) + 15); 
      else if("C".equals(key)) 
       concurrentHashMap.put(key, concurrentHashMap.get(key) +10); 
      }else 

      if("Science".equals(Thread.currentThread().getName())) { 
       if("A".equals(key)) 
        concurrentHashMap.put(key, concurrentHashMap.get(key) +19); 
       else if("B".equals(key)) 
        concurrentHashMap.put(key, concurrentHashMap.get(key) +14); 
       else if("C".equals(key)) 
        concurrentHashMap.put(key, concurrentHashMap.get(key) +9); 
       } 
      else 
       if("English".equals(Thread.currentThread().getName())) { 
        if("A".equals(key)) 
         concurrentHashMap.put(key, concurrentHashMap.get(key) +18); 
        else if("B".equals(key)) 
         concurrentHashMap.put(key, concurrentHashMap.get(key) +13); 
        else if("C".equals(key)) 
         concurrentHashMap.put(key, concurrentHashMap.get(key) +8); 
        } 

      } 
     // } 
      } 
      finally{ 

       System.out.println("Completed " + Thread.currentThread().getName() + " : " + concurrentHashMap); 
       countDownLatch.countDown(); 
      } 
     } 
     } 
+4

什麼辦法? 'Concurrent'(在'ConcurrentHashMap'中)意味着,爲了保護其內部結構,映射儘可能地保持同步。這並不意味着,使用它會自動修復使用地圖的代碼中的競爭條件。 – Dirk

+0

'concurrentHashMap.put(key,concurrentHashMap.get(key)+19);'不是原子的:地圖可以在get和put之間更新... – assylias

+0

你沒有正確使用它顯示的代碼!我建議你從閱讀接口ConcurrentMap(ConcurrentHashMap是一個實現)的javadocs開始,特別是理解爲什麼需要新方法 – Scorpion

回答

1

我不認爲你在你的測試需要ConcurrentHashMap。您在線程執行之前初始化映射。相反,你可以使用普通HashMap通過String鍵和AtomicInteger值參數化:

HashMap<String, AtomicInteger> concurrentHashMap = ... 
concurrentHashMap.put("A", new AtomicInteger(0)); 
... 

然後你就可以原子增加每個線程AtomicInteger實例的值:

concurrentHashMap.get(key).addAndGet(20); 
相關問題