Why is run() not immediately called when start() called on a thread object in java
Asked Answered
L

6

7

Or is it?
I have a thread object from:

Thread myThread = new Thread(pObject);

Where pObject is an object of a class implementing the Runnable interface and then I have the start method called on the thread object like so:

myThread.start();

Now, my understanding is that when start() is called, the JVM implicitly (and immediately) calls the run() method which may be overridden (as it is in my case)

However, in my case, it appears that the start() method is not called immediately (as desired) but until the other statements/methods are completed from the calling block i.e. if I had a method after the start() call like so:

myThread.start();
doSomethingElse();

doSomthingElse() gets executed before the run() method is run at all.
Perhaps I am wrong with the initial premise that run() is always called right after the start() is called. Please help! The desired again is making executing run() right after start(). Thanks.

Lenis answered 22/4, 2010 at 11:10 Comment(1)
You can call Thread.yield() to "release" the CPU for other threads, but that doesn't mean you new thread is the next one.Touristy
C
13

Now, my understanding is that when start() is called, the JVM implicitly (and immediately) calls the run() method ...

That is incorrect. It does implicitly call run(), but the call does not necessarily happen immediately.

The reality is that the new thread becomes available to be scheduled at some point in time after the start() call is made. The actual scheduling is up to the native scheduler. It could happen immediately, or the parent thread could continue for a period before the child thread is scheduled.

To force your thread to start running immediately (or to be more accurate, to start running before doSomethingElse()), you need to do some explicit synchronization; e.g. something like this:

    java.util.concurrent.CountDownLatch latch = new CountdownLatch(1);
    new Thread(new MyRunnable(latch)).start();
    latch.await(); // waits until released by the child thread.
    doSomethingElse();

where

class MyRunnable implements Runnable {
    private CountDownLatch latch;
    MyRunnable (CountDownLatch latch) { this.latch = latch; }
    public void run() {
        doSomeStuff();
        latch.countDown(); // releases the parent thread
        doSomeMoreStuff();
    }
    ...
}

There are other ways to implement the synchronization using the concurrency classes, or Java's mutex / wait / notify primitives1. But explicit synchronization between the two threads is the only way to guarantee the behavior that you require.

Note that the doSomething() call in the child thread will complete before the parent thread is released, but we can say nothing about the order of execution of doSomethingElese() and doSomeMoreStuff(). (One might run before the other and vice versa, or they might run in parallel.)


1 - Using wait / notify is not recommended, but it may be your only option if the concurrency APIs are not available; e.g. on Java ME.

Cloots answered 22/4, 2010 at 11:50 Comment(0)
K
17

Um... the run() method will run in a different thread. That, per definition, means you cannot make any assumptions about before or after which statements in the current thread it will execute, unless you synchronize them explicitly.

Kabuki answered 22/4, 2010 at 11:14 Comment(0)
N
13

run() is the first thing within your code that the new thread does, but there's some set-up work that the new thread does first, and there's no guarantee that any significant amount of work will by done by the new thread before the original thread goes on to call doSomethingElse().

You're right in thinking that there are no guarantees here. Making assumptions about the behaviour of multithreaded code is the source of much pain - try not to do it!

Nakitanalani answered 22/4, 2010 at 11:12 Comment(1)
+1 "Making assumptions about the behaviour of multithreaded code is the source of much pain - try not to do it!"Buoyage
C
13

Now, my understanding is that when start() is called, the JVM implicitly (and immediately) calls the run() method ...

That is incorrect. It does implicitly call run(), but the call does not necessarily happen immediately.

The reality is that the new thread becomes available to be scheduled at some point in time after the start() call is made. The actual scheduling is up to the native scheduler. It could happen immediately, or the parent thread could continue for a period before the child thread is scheduled.

To force your thread to start running immediately (or to be more accurate, to start running before doSomethingElse()), you need to do some explicit synchronization; e.g. something like this:

    java.util.concurrent.CountDownLatch latch = new CountdownLatch(1);
    new Thread(new MyRunnable(latch)).start();
    latch.await(); // waits until released by the child thread.
    doSomethingElse();

where

class MyRunnable implements Runnable {
    private CountDownLatch latch;
    MyRunnable (CountDownLatch latch) { this.latch = latch; }
    public void run() {
        doSomeStuff();
        latch.countDown(); // releases the parent thread
        doSomeMoreStuff();
    }
    ...
}

There are other ways to implement the synchronization using the concurrency classes, or Java's mutex / wait / notify primitives1. But explicit synchronization between the two threads is the only way to guarantee the behavior that you require.

Note that the doSomething() call in the child thread will complete before the parent thread is released, but we can say nothing about the order of execution of doSomethingElese() and doSomeMoreStuff(). (One might run before the other and vice versa, or they might run in parallel.)


1 - Using wait / notify is not recommended, but it may be your only option if the concurrency APIs are not available; e.g. on Java ME.

Cloots answered 22/4, 2010 at 11:50 Comment(0)
R
6

When you call myThread.start(), your thread becomes available for execution. Whether it will actually gain CPU, and for how long -- it's up the the OS scheduler. In fact, your run() may be getting control immediately, but losing it before it can do anything you can notice. The only way to ensure that your thread executes what you need before doSomethingElse() is to use explicit synchronization.

Roger answered 22/4, 2010 at 11:19 Comment(0)
M
3

You've started a new thread. That thread runs in parallel to the thread that started it so the order could be:

pObject.run();
doSomethingElse();

or

doSomethingElse();
pObject.run();

or, more likely, there will be some crossover. pObject.run() may run in the middle of doSomethingElse() or vice versa or one will start before the other finishes and so on. It's important to understand this and understand what is meant by an atomic operation or you will find yourself with some really hard-to-find bugs.

It's even more complicated if two or more threads access the same variables. The value in one may never be updated in one thread under certain circumstances.

I highly suggest:

  1. You don't make your program multi-threaded unless you absolutely need to; and

  2. If you do, buy and read from cover to cover Brian Goetz's Java Concurrency in Practice.

Markman answered 22/4, 2010 at 11:16 Comment(1)
"That thread runs in parallel to the thread that started it ...". Not necessarily. For example on a platform where there is only one core (and no hyperthreading) the two threads' execution may be interleaved, but they cannot possibly run in parallel.Cloots
M
0

calling the start method on a Thread Object may not make the jvm invoke the run() method immidiately, rather it makes the thread a runnable and ready for execution, in this case the parent thread first executes its code and then passes control to the child thread, if u want the child thread to execute before the parent thread code is executed use the chileThreadObject.join() method in the parent thread.

Mcadoo answered 23/10, 2018 at 23:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.