-3

I'm learning about multi-threading in Java and was experimenting with threads. I came up with a sort of racing condition code (sort of... excuse this noob) where 2 threads work in a loop (100 times) and races to change a static variable. The goal is when a thread first completes the loop (either running in time-slicing environment or parallelly) the value of the variable is printed and system.exit(int status) is called to terminate program! This is to just find out which thread won the race!

The expected output should be: nameOfTheThreadThatWonTheRace + "--" + valueOf'I'IncrementedInTheLoop

Here is the code:

public class Nest
{
  public static void main(String[] args) throws Exception
  {
    Thread r1 = new Thread(new Racer(),"R1");
    Thread r2 = new Thread(new Racer(),"R2");
    r1.start();
    r2.start();
  }
}

class Racer implements Runnable
{
  public void run()
  {
    for(int i = 0; i <= 100; i++)
    {
      Value.value = Thread.currentThread().getName() + "--" + i;
    }
    Value.printValue();
    System.exit(0);
  }
}

class Value
{
  static String value = null;

  public static void printValue()
  {
    System.out.println(value);
  }
}

However actual output is different (4 runs):

  1. R2--100 R2--100

  2. R2--84 R2--100

  3. R1--100 R1--100

  4. R2--39 R2--100

I'm at loss at why is JVM not halting after any one of the thread reaches 'System.exit(0)' line? Does exit() only shuts down main thread or entire JVM or are the still-executing-threads are stopping the JVM to halt?

Also please explain to me why 2 lines of o/p are being produced?

For extra info:
Processor--> Intel® Core™ i5-7200U CPU @ 2.50GHz × 4 
Ram--> 8GB
OS--> Fed27 workstation

(I'm not yet exposed to java.util.concurrent API 'yet' but I know I can manage threads differently there..)

I appreciate if you can explain in normal threading terms instead of referring to the Concurrent API.

Thanks for help and excuse this noob once again :)

  • I didn't read all of the code, but it's completely thread **unsafe**, so...any surprises you encounter is because of that. Read some tutorials on multithreaded programming and you'll be fine. – Kayaman Feb 02 '18 at 11:33
  • I know it's not thread safe...that's actually the expected behaviour (I guess) but I'm wondering why System.exit() not working... – ShashiKanth Chill Feb 02 '18 at 11:48
  • Can you explain a bit more and mention the exact output you are expecting? What's wrong with the actual outputs? They seem to be correct as per your program. – Rahul Feb 02 '18 at 11:50
  • `System.exit()` is working just fine. It's your code that's broken and your expectations that are wrong, so it's not very useful to wonder at its output. – Kayaman Feb 02 '18 at 11:52
  • The o/p I'm expecting is the thread that completed the loop first should print out the 'value' and the program should terminate at that point regardless of other threads... If my program is wrong...can you please help me correct it to get expected outcome or any other pointers will be helpful – ShashiKanth Chill Feb 02 '18 at 11:53
  • Your biggest mistake is writing code that isn't threadsafe and then expecting it to work in a reliable and deterministic way. This is not a good way to learn. – Kayaman Feb 02 '18 at 12:03

3 Answers3

1

It takes time to process System.exit(0) so while the thread that calls it is waiting for the Operating System to kill and reclaim the code that is running on the different cores, the code that is running on the different cores can complete. This makes it look like both threads "won the race".

Remember that in a multi-threaded environment, one thread doesn't have explicit control over the timing of another; not even in system shutdown. If you want that kind of control, you need to write it into the program explicitly (such as by having both threads checking a thread-safe flag, to determine if the race is still being run).

Edwin Buck
  • 69,361
  • 7
  • 100
  • 138
  • Thank you... I think I understood what you said..so even if the code is one core is killed...the remaining threads in other code, since they are still running can stop the JVM from halting...did it get it right? – ShashiKanth Chill Feb 02 '18 at 12:04
  • @shashikanthchillappagari The other threads don't stop the JVM from halting, they just finish up after one thread calls the `System.exit(0)` and before the operating system forcibly terminates the threads that didn't call `System.exit(0)`. It takes time for the `System.exit(0)` to run too! Of course, there are other issues with your program, but assuming that the JVM is fully removed from all cores the instant that `System.exit(0)` is called is not how things work. The thread calling `System.exit(0)` makes a request to the Operating System, which then handles it, taking time. – Edwin Buck Feb 02 '18 at 13:16
0

Calling System.exit() will shut down the JVM (please see the javadocs or the language specs).

The static member of Value is being updated by both threads in parallel. The outcome of such an unsafe update is not defined. This is why you see the strage output.

A solution would be to use local variables or fields within the Racer class, as you do not have to share data between your two threads. Furthermore, you even do not need that, as you could get the current thread's name with Thread.currentThread().getName()

werner
  • 13,518
  • 6
  • 30
  • 45
0

I think if you add a little logging to your program, then it can help you to understand what is really going on:

    public void run()
      {
        for(int i = 0; i <= 100; i++)
        {
        if(i==100)
        {
            System.out.println(Thread.currentThread().getName() +" : before setting value 100th time : " + System.currentTimeMillis());
        }
          Value.value = Thread.currentThread().getName() + "--" + i;
          if(i==100)
        {
            System.out.println(Thread.currentThread().getName() +" : after setting value 100th time : " + System.currentTimeMillis());
        }
        }
        System.out.println(Thread.currentThread().getName() +" : before printing : " + System.currentTimeMillis());
        Value.printValue();
        System.out.println(Thread.currentThread().getName() +" : before exiting : " + System.currentTimeMillis());
        System.exit(0);
      }


class Value
{
  static String value = null;

  public static void printValue()
  {
    System.out.println(Thread.currentThread().getName() + " : value : " + value + " : " + System.currentTimeMillis());
  }
}

First thing, If any thread calls a System.exit(), then the JVM terminates(killing all threads!!!). It will not wait for any thread to execute but it calls shutdown hooks, uninvoked finalizers, etc. So, it may take sometime for the JVM to finish. You can read more here:

https://docs.oracle.com/javase/7/docs/api/java/lang/Runtime.html#exit(int)

Now, you have mentioned outputs from only 4 runs. If you run it few more times, I'm sure you will get the below output:

R2--100

This clearly means that the JVM terminated before the other thread could execute.

Now for your outputs, say

R2--100 R2--100

Both thread executed before the JVM could terminate, simple!

One thing to notice is that both thread's name is R2. This is because value variable is static and being shared between the 2 threads. Due to the race condition, before R2 can print the value, it's being set by R1. You can see this if you add the logging that I suggested.

See below sample output:

R2 : before setting value 100th time : 1517579707689
R2 : after setting value 100th time : 1517579707690
R1 : before setting value 100th time : 1517579707689
R1 : after setting value 100th time : 1517579707691
R2 : before printing : 1517579707691
R1 : before printing : 1517579707692
R2 : value : R1--100
R1 : value : R1--100
R2 : before exiting : 1517579707694
R1 : before exiting : 1517579707694
Rahul
  • 637
  • 5
  • 16