Reputation: 486
I am currently learning Multithread in Java in my programming class. From what I have understood, the order of execution for different threads cannot be predicted so it is important to ensure that we implement the mechanism to make sure everything is executed in the desired order.
One of the mechanisms that I have learn is to use Thread.join()
which forces one thread to wait until the other threads finished executing. However, the following example code makes me actually more confused:
Runnable hello = () -> {
System.out.print("H");
System.out.print("e");
System.out.print("l");
System.out.print("l");
System.out.print("o\n");
};
Runnable world = () -> {
System.out.print("W");
System.out.print("o");
System.out.print("r");
System.out.print("l");
System.out.print("d\n");
};
Thread t1 = new Thread(hello);
Thread t2 = new Thread(world);
t1.start();
t2.start();
try {
t1.join();
t2.join();
System.out.println("Finished");
} catch (InterruptedException ie) {
System.out.println("Interruption");
}
Supposedly this code should demonstrate how .join()
works which will execute hello()
and then world()
resulted in a properly printed "Hello World"
.
However, when I actually run the code, the order of execution seems still to be random. I got results like
// #1
WoHerld
llo
Finished
// #2
HWello
orld
Finished
// And others
So, what is the purpose of using .join()
is the order of execution is still "messed up" like this?
And what should I do here to make sure I can have a properly printed result every time I run the code?
Upvotes: 0
Views: 235
Reputation: 719281
The purpose of join()
is to wait until a given thread has finished. It doesn't cause the thread to finish, or alter the behavior of the thread in any other way1.
If you really want all of t1
s output to appear before all of t2
s output, then you could write the code like this:
try {
t1.start();
t1.join();
t2.start();
t2.join();
System.out.println("Finished");
} catch (InterruptedException ie) {
System.out.println("Interruption");
}
However, the point of using threads is to allow tasks to be run at the same time. If your problem requires you to constrain the tasks to run one after another (i.e. NOT at the same time) then threads do not help.
So in your example, the simple way to get sequential output is to run the tasks on the same thread, one after the other. And (all other things being equal) you may as well do it on the main thread.
// Don't use threads at all
hello();
world();
1 - In fact if a t.join()
call did somehow alter the way that t
behaved before the call, that would be a causality violation. That is not possible to implement with a classical physics or a conventional computer. The current mathematical models of quantum computation don't violate causality either, but this is likely to be moot in the context of Java-like threads.
Upvotes: 2
Reputation: 44210
What if the gap here was a few seconds? (you could even simulate it by throwing a Thread.sleep()
in there)
t1.start();
t2.start();
// Here
t1.join();
t2.join();
Both of your threads would already have finished by the time you called join
, so that should be a clue that join
is not having any effect on them.
If you want to print 'Hello' then 'world', you can rearrange the order to
t1.start();
t1.join();
t2.start();
t2.join();
Of course, there is no concurrency or parallelism here. You're just doing one thing and then another thing on two different threads.
Upvotes: 1
Reputation: 1226
Join in this case only demonstrates that the last line "Finished" is always correct. The two threads individually printing characters cannot guarantee order as both are writing to the same output buffer, in this case stdout
(or System.out
).
Guaranteeing order of execution is in the territory of using locks or mutexes, in the case of Java the synchronized
keyword.
Upvotes: 4