Java streams - start () and run () - lost line in console
Why is another "TaskImpl run ()" missing in Scenario 1?
Scenario 1: if the line marked with 1. is before the line marked with 2. this is displayed on the console:
TaskImpl run ()
ThreadImpl run ()
ThreadImpl run ()
Finished
Scenario 2. If the line marked with 2. is before the line marked with 1. this is displayed on the console:
TaskImpl run ()
TaskImpl run ()
ThreadImpl run ()
ThreadImpl run ()
Finished
My code:
public class ThreadTest {
public static void main(String[] args)
{
Thread t1 = new ThreadImpl();
Thread t2 = new Thread(new TaskImpl());
t1.start();
t2.start();
t1.run(); // 1.
t2.run(); // 2.
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Finished");
}
}
class ThreadImpl extends Thread {
@Override
public void run() {
try {
Thread.sleep(2000);
System.out.println("ThreadImpl run()");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class TaskImpl implements Runnable {
@Override
public void run() {
try {
Thread.sleep(1000);
System.out.println("TaskImpl run()");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
source to share
As you can see in the implementation, the Thread#run
method run
target
( Thread
implementation / subclass that should run on the thread) will only be called if target
not null
:
@Override
public void run() {
if (target != null) {
target.run();
}
}
Now, another piece of information: if the thread has completed its task, it calls the privateexit
method, which sets target
in null
(*):
private void exit() {
// [omitted code lines]
/* Aggressively null out all reference fields: see bug 4006245 */
target = null;
// [omitted code lines]
}
So, if you called start
on a thread and did your job, you can't call again run
... well, you can, but I won't do much.
Now, consider your first version of your code:
t1.start(); -> starts a thread; takes at least 2 seconds to finish
t2.start(); -> starts a thread; takes at least 1 second to finish
t1.run(); -> blocks main thread; takes at least 2 seconds to finish
t2.run(); -> called after `t1.run()` finished;
So, as you can see, it t2.run()
will work at least 2 seconds after t2.start()
because it t1.run()
blocks the method call. So, t2
(of t2.start()
) is already finished and set target
to null
, so it t2.run()
completes the check target != null
and does "nothing".
Now the second version:
t1.start(); -> starts a thread; takes at least 2 seconds to finish
t2.start(); -> starts a thread; takes at least 1 second to finish
t2.run(); -> blocks main thread; takes at least 1 seconds to finish
t1.run(); -> called after `t2.run()` finished;
Where you t2.run()
can work before t2
of t2.start()
could finish his "dream", so target
it is still installed correctly.
And t1.run()
also has no problem because it calls the overriden method directly run
ThreadImpl
, so it doesn't need to pass the check. And it would be difficult to pass it anyway, because it t2.run()
sleeps for 1 second, so t1
from t1.start()
still asleep even a second, and it target
is also still installed.
This is why you get "full" output.
I hope my explanations are clear and you understand the reason for the different results :).
(*) Please remember that this behavior is different from other Java environments. But the Oracles version and OpenJDK do it.
source to share