2012-03-08 88 views
0

我試圖測試一些關於在多個線程之間共享迭代器的事情。我寫了一個非常簡單(並且非常愚蠢)的程序,它應該在兩個不同的線程中遍歷相同的地圖。下面的代碼:多線程未按預期工作

final Map<Integer, Integer> m = new HashMap<Integer, Integer>(); 
    final Random r = new Random(); 
    for(int i = 0; i< 1000 ; i++){ 
     m.put(r.nextInt(10000), r.nextInt(10000)); 
    } 
    Thread t1 = new Thread(new Runnable(){ 

     @Override 
     public void run() { 
      // TODO Auto-generated method stub 
      Iterator<Integer> it = m.keySet().iterator(); 
      it.next(); 
      for(Integer i : m.keySet()){ 
       System.out.println("T1 " + i); 
       try { 
        Thread.sleep(r.nextInt(100)); 
       } catch (InterruptedException e) { 
        // TODO Auto-generated catch block 
        e.printStackTrace(); 
       } 
      } 
     } 

    }); 

    Thread t2 = new Thread(new Runnable(){ 

     @Override 
     public void run() { 
      // TODO Auto-generated method stub 
      Iterator<Integer> it = m.keySet().iterator(); 
      it.next(); 
      for(Integer i : m.keySet()){ 
       System.out.println("T2 " + i); 
       try { 
        Thread.sleep(r.nextInt(100)); 
       } catch (InterruptedException e) { 
        // TODO Auto-generated catch block 
        e.printStackTrace(); 
       } 
      } 
     } 

    }); 

    t1.run(); 
    t2.run(); 

現在,當我運行此我期待要麼得到某種形式的併發修改,或兩者「T1」並在控制檯「T2」的消息混合物例外。會發生什麼事是我的程序輸出線程1的映射的所有值然後THEN進展到線程2.爲什麼在這裏可序列化的行爲?

回答

6

您需要致電t1.start()t2.start()而不是run

調用run將簡單地執行您的run方法中的代碼。
start是啓動一個新的線程。

+0

哇......真的很抱歉,這樣一個愚蠢的問題。感謝您的及時回覆。 – Bober02 2012-03-08 00:15:03

+3

沒問題。我只是很快注意到這一點,因爲我過去曾多次犯過同樣的錯誤。我認爲線程的API在這方面的設計有點差 - 這很容易犯這個錯誤。 – Tim 2012-03-08 00:16:42

+0

@Tim我完全同意這一點。 Bober02,我想幾乎每個人都在某個時候犯了這個錯誤,所以不要爲此而出汗。這是Thread的「there/they/their」。 :) – yshavit 2012-03-08 00:19:08

2

由於您正在執行t.run()而不是t.start(),因此您正在單線程(主線程)中執行操作。

話雖如此,注意使用兩個線程並不總是導致交錯執行;經常按順序執行操作的效率更高,因此JVM將按順序調度實際操作。另外,對標準哈希映射的併發修改檢測是盡力而爲的,而不是保證機制。