0

When i run the following code, the program never exits and gets stuck in the while loop which should be the expected behaviour.

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) {}
    }
}

With the join() uncommented the program always exits. Moreover, When I modified the code to print the the sequence in which the threads run, with the join in place, I observed that Thread-0 first completes its task followed by Thread-1 and so on in proper numbering sequence.

Is this expected behaviour or just one of the idiosyncrasies of the JVM scheduler?

azuri
  • 61
  • 6
  • That's called a [race condition](https://en.wikipedia.org/wiki/Race_condition) – litelite Aug 17 '17 at 14:05
  • Race condition when commented but not when uncommented. That is the question. – azuri Aug 17 '17 at 14:09
  • 3
    You don't have a race when uncommented because the `join` forces the main thread to wait for the thread to be finished before starting a new one. So you only have one thread at a time. – litelite Aug 17 '17 at 14:11
  • @litelite, how silly of me to put the join inside the loop. Thanks! – azuri Aug 17 '17 at 14:13
  • this is not a race condition, it is just doing what you are telling it to do in the for loop, which is run a thread and wait until it is done via the `.join()` then run another. –  Aug 17 '17 at 14:13
  • You should really learn how to use the `Executor Service` correctly and you will not have these issues. [It exists for a reason.](https://stackoverflow.com/questions/1250643/how-to-wait-for-all-threads-to-finish-using-executorservice?rq=1) –  Aug 17 '17 at 14:14
  • @JarrodRoberson, one step at a time :) – azuri Aug 17 '17 at 14:15
  • 1
    @azuri, If I was a teacher, I'd teach my students to use `Executors.newFixedThreadPool(n)` _before_ teaching them to use `Thread`. – Solomon Slow Aug 17 '17 at 16:10

1 Answers1

1

yes this is the expected behavior, with your join commented, more than thread will have access to your set in the same time, you will have race condition , in a case where count will be the same for more than thread so basically you will be adding more than one element in the same place so you will not have your expected number of items in the set hence the loop condition will always be true and your app wont exit.

with your join not commented, main thread will be blocked until each thread is finished, when the first thread starts and the main thread moves to the join, the main thread will be blocked and wait the first thread to finish before moving to the next iteration of the loop, so you wont have any concurrent access to "count" hence all the added elements will be different

Amer Qarabsa
  • 6,412
  • 3
  • 20
  • 43
  • My question isn't about the first case where i agree race condition is the cause of repeated count values. My question is why there is no race condition in the second case when i have uncommented the join(). – azuri Aug 17 '17 at 14:08
  • @azuri i added an explanation for it, check it please – Amer Qarabsa Aug 17 '17 at 14:09
  • Concurrent mutation of `HashSet` can also cause many problems. See this question for some details https://stackoverflow.com/q/22632552/1398418 @azuri – Oleg Aug 17 '17 at 14:23