2017-08-17 108 views
0

当我运行下面的代码时,程序永远不会退出并卡在while循环中,这应该是预期的行为。Java线程连接创建线程的顺序运行

public class MyClass implements Runnable { 
    public static final int NO_OF_THREADS = 100; 
    private static int count; 
    private static Set<Integer> set = new HashSet<>(); 
    @Override 
    public void run() { 
     for(int i=0 ;i<10000; i++) { 
      set.add(count++); 
     } 
    } 
    public static void main(String[] args) throws Exception { 
     Thread[] threadArray = new Thread[NO_OF_THREADS]; 
     for(int i=0; i<NO_OF_THREADS; i++) { 
      threadArray[i] = new Thread(new MyClass()); 
     } 
     for(int i=0; i<NO_OF_THREADS; i++) { 
      threadArray[i].start(); 
      //threadArray[i].join(); 
     } 
     while(set.size()!=1000000) {} 
    } 
} 

随着join()取消注释,程序总是退出。此外,当我修改代码以打印线程所运行的序列并加入适当位置时,我发现Thread-0首先完成其任务,之后是Thread-1,然后以适当的编号顺序完成。

这是预期行为还是JVM 调度程序的特性之一?

+0

这就是所谓的[竞争条件](https://en.wikipedia.org/wiki/ Race_condition) – litelite

+0

比赛条件评论但未注释时。就是那个问题。 – azuri

+3

因为'join'强制主线程在开始新线程之前等待线程完成,所以未注释时没有比赛。所以你一次只有一个线程。 – litelite

回答

1

是的这是预期的行为,与您的连接评论,超过线程将有权访问您的设置在同一时间,你将有竞争条件,在计数将相同的多于线程,所以基本上你会在同一个地方添加多个元素,所以你不会在设置中有你期望的项目数量,因此循环条件将始终为真,并且你的应用程序不会退出。

与您的连接没有评论,主线程将被阻塞,直到每个线程完成,当第一个线程开始,并且主线程移动到连接,主线程将被阻止,并等待第一个线程完成前移动到循环的下一个迭代,所以你不会有任何并发​​访问“计数”,因此所有添加的元素将会不同

+0

我的问题不是关于第一种情况,我同意竞赛条件是重复计数值的原因。我的问题是为什么在第二种情况下我没有注释join()时没有竞争条件。 – azuri

+0

@azuri我为它添加了一个解释,请检查它 –

+0

'HashSet'的并发变异也会导致很多问题。看到这个问题的一些细节https://stackoverflow.com/q/22632552/1398418 @azuri – Oleg