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();
        }
    }
}

      

+3


source to share


1 answer


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.

+3


source







All Articles