I'm having trouble understanding why this code is printing "Apple" instead of "Orange" after multiple runs. Can anyone help?
public class Fruit {
public static String fruit;
public static void main(String args[]) throws InterruptedException {
try {
Thread t = new AppleThread();
t.start();
} catch (IllegalThreadStateException e) {
System.out.println("Thread generated an error.");
}
fruit = "Orange";
Thread.sleep(100);
System.out.println(fruit);
}
private static class AppleThread extends Thread {
@Override
public void run() {
fruit= "Apple";
}
}
}
The core of it for me has two questions: 1.) When referring to Thread.sleep(100) which thread is it referring to?
2.) We do t.start() in parallel to the main thread which assigns message = "orange". However, Apple is always what is printed out, why is this? "Apple" seems like it always gets the last assignment.
General clear up for this is greatly appreciated.
1.) When referring to Thread.sleep(100) which thread is it referring to?
The current thread which at the moment executes the piece of code containing the statement. In this case it is the main thread. It gives t
a chance to do what it is supposed to do, otherwise the main thread would terminate an so the whole process without caring about t
at all.
If you put Thread.sleep
in the run method of t
, then t goes to sleep.
2.) why always "Apple"?
What you're experiencing is the main
thread creating a new thread t
and calling its start
method.
But this doesn't mean that now t
actually runs and main does not. main
continues its execution in parallel until it goes to sleep after the assignment fruit = "Orange";
.
Maybe in the meantime t
even gets a bit of cpu, but not enough to reach fruit= "Apple";
. Only after main
sleeps it can execute, so fruit
as it happens always ends up as Apple
, but not necessarily so.
Note, that this is the behavior at your machine/operating system/java application right now. Under different circumstances t
might actually get enough cpu to fully execute before main
reaches its assignment, then you'd be left with an Orange.
You actually have a race condition built into your code, which lacks synchronization. What you seen now might look sequential. Start another few threads, use another operating system or cpu and something else might happen. It depends how the threads are scheduled, which one draws first or just when. Potentially they're parallel, even to the degree that both write simultaneously to the variable. Which is another discussion.
You ran your code a few times, always the same result. Run it 100.000 times, maybe always the same result, just except one time. Or just once a year or once per system life time. That's also the reason, why concurrency bugs or race conditions are so hard to track down, everybody avoids hand-crafted concurrent mutations and synchronization like the plague and uses immutable data and pre-mediated processing instead, like e.g. java parallel streams, or chooses to avoid to work in the field altogether and grow potatoes instead or whatever.
Btw. try to put Thread.sleep(100);
before fruit = "Orange";
and see, what is happening then. Or perhaps, instead of assigning just once per thread, call a separate method that repeatedly does something and yields, that might make it more transparent. It also creates a situation, where 2 threads run the same piece of code.
public static void printSome() {
IntStream.range(0, 100).forEach(i -> {
System.out.println(String.format("Thread %d says:%d", Thread.currentThread().getId(), i));
Thread.yield();
});
}