2012-03-08 91 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将按顺序调度实际操作。另外,对标准哈希映射的并发修改检测是尽力而为的,而不是保证机制。