5

I know that "Once a thread has been started, it can never be started again".
But I want to know why?
What's the wrong if it is allowed to start again later in another time?
Why, the only time you can start a thread is when it is in the NEW state? Why it can't be also after DEAD at least?

public class ThreadDemo {

    public static void main(String[] args) {

        Thread thread = new Thread(new MyRunnable());
        thread.start();
        thread.start(); // java.lang.IllegalThreadStateException

    }

}

class MyRunnable implements Runnable{

    @Override
    public void run() {

        System.out.println("run().Thread.currentThread().getName() : " + Thread.currentThread().getName());

    }
}

Note : I have gone through these posts. But my question is much more specific and descriptive.

Here, please note that I want to know this mainly to understand the threads internal functionalities and how the related aspects like GC works with thread states.

Community
  • 1
  • 1
ironwood
  • 8,936
  • 15
  • 65
  • 114
  • 1
    If you look at the life cycle of a thread, it is created and then moved to a thread pool where it waits to be executed - once its work has been done it is destroyed by the scheduler and therefore the system no longer knows about it (null reference) - therefore it cannot be started again - as Elliot suggests below it is perfectly fine to crate a new Thread which does work of the `MyRunnable` function, but a named threads execution is unique to its scope. – Halfpint Dec 27 '14 at 23:39
  • 2
    @Alex this should be posted as an answer. It is much better explained then Elliot's ! – Leonardo Dec 27 '14 at 23:45
  • yep. New thread will go to the pool once the start() is invoked. We have the reference in hand to invoke start() again. But what I'm asking is why is it not allowed to be Runnable again at least after the state is dead. If it allowed it what could be the problems? – ironwood Dec 27 '14 at 23:47

3 Answers3

5

Because the Thread implementation does not allow it. You could always create another Thread instance with your Runnable like

new Thread(new MyRunnable()).start();
new Thread(new MyRunnable()).start();

Edit

JLS-17.4.3. Programs and Program Order says (in part),

A set of actions is sequentially consistent if all actions occur in a total order (the execution order) that is consistent with program order, and furthermore, each read r of a variable v sees the value written by the write w to v such that:

w comes before r in the execution order, and

there is no other write w' such that w comes before w' and w' 
comes before r in the execution order.

Sequential consistency is a very strong guarantee that is made about visibility and ordering in an execution of a program. Within a sequentially consistent execution, there is a total order over all individual actions (such as reads and writes) which is consistent with the order of the program, and each individual action is atomic and is immediately visible to every thread.

If Thread instances could start again then the implementation of sequential consistency may well be impossible.

Community
  • 1
  • 1
Elliott Frisch
  • 198,278
  • 20
  • 158
  • 249
  • 3
    Understood. But why? What I'm asking is why is it not allowed to be Runnable again at least after the state is dead. If it allowed it what could be the problems? – ironwood Dec 27 '14 at 23:48
  • Perhaps my example was poor, any thread might share state with another thread (and in fact many do - being that Java is not a purely functional language and functions aren't required to behave [idempotently](http://en.wikipedia.org/wiki/Idempotence#Computer_science_meaning)); your contrived example is the exception (not the rule). To provide sequential consistency a dead thread can't restart. – Elliott Frisch Dec 28 '14 at 02:53
  • How any thread share state with another thread? By mentioning "state" are you referring to the thread state (NEW, DEAD etc) or are you referring to it's variable states? As per my knowledge, variable states declared within the Runnable are not getting shared unless they are static right? can you explain how a dead thread violate the sequential consistency if dead thread is restarted? – ironwood Dec 28 '14 at 03:36
  • @Namalak Again your example doesn't consider that `Thread a` might (for example) also start `Thread b` and then `join()` on the results. Perhaps (depending on context) it starts `Thread c` or `Thread d`; again I guess they could have given a `Thread` semantics to allow a transition from `DEAD` to `NEW` but Sun (now Oracle) didn't/haven't. Also, it would seem to me that inner classes (and now lambdas) wouldn't have a consistent memory model and I think that's ultimately why they didn't. – Elliott Frisch Dec 28 '14 at 03:41
  • O..K.. Some points yet to be examined further. But thank you for the facts and points you mentioned Elliott. Appriciate! – ironwood Dec 28 '14 at 12:42
3

I can give you some points.

  1. Garbage Collection: Active threads are considered as roots for Garbage Collection. Means to say if some object is reachable from an active thread then it cannot be garbage collected.
    Now if a thread is inactive (dead) any gc algorithm will determine that if a particular object which was only reachable by that thread is now eligible for Garbage Collection then it will collect that object. But now if you again make your thread active its a problem because it will have a corrupted view of its stack because many objects might have been garbage collected. Your whole program will go haywire.

    To workaround this problem you will have maintain one more state lets call it GC_COLLECTABLE. It means thread is active means that its status != GC_COLLECTABLE. Now then the question arises how ad when the programmer will set this status. Its kind of same problem where cannot stop a thread or determining when certain objects must garbage collected. Its in itself a very complex problem to solve. The easiest way to workaround this problem is to not have a thread active once its dead or cannot restart it.

  2. thread.join(): As Eliott suggested . Suppose there are three threads T1 T2 and a restartable thread RST. Now suppose T1 and T2 both call RST.join(). Problem when T1 and T2 will get out of join. If threads can be started again then join method is infinite. If you allow join to return after a DEAD state then there is race and undetermined behavior causing T1 to finish join() but T2 still lingering because RST has been already re started.

  3. API change: How do you suggest this should be implemented.

    Thread.start(); // Would this method suffice. Probably not

    What will happen if i called Thread.start() in a loop -> will it will create new threads if previous threads are not dead or will restart the dead threads (Sounds like Executors.newCachedThreadPools)

    -> or throw Exceptions if a the current thread is not dead or restart the thread Not a very good way this will make your program more non-deterministic. Because the same thread can take variable amount of time for the same task therefore you will have problem predicting your program output. And at the least you need a signature change for a checked exception from a start method or define a new method restart but it will have the same problem as above.

From my perspective the first point is alone enough to move from restarting the thread. Also you can have the similar functionality by using ThreadPools where a thread can be reused for different/similar tasks

veritas
  • 2,444
  • 1
  • 21
  • 30
0

If you look at the life cycle of a thread, it is created and then moved to a thread pool where it waits to be executed

Once its work has been done it is destroyed by the scheduler and therefore the system no longer knows about it (null reference) - therefore it cannot be started again, as Elliot suggests it is perfectly fine to create a new Thread which does work of the MyRunnable function, but a named threads execution is unique to its scope

Halfpint
  • 3,967
  • 9
  • 50
  • 92
  • Yep! New thread will go to the pool and be Runnable once the start() is invoked. We have the thread reference in hand to invoke start() again. But what I'm asking is why is it not allowed to be Runnable again at least after the state is dead. If it allowed it what could be the problems? – ironwood Dec 27 '14 at 23:50
  • 1
    @ Alex : Thank you for the explanation. But what would the garbage collector destroy? Is it thread object? or thread of execution? I thought it would not destroy the thread object since we haven't nullify the reference. And when it throws the illegalArgumentException when try to call it again. If it destroy the thread of execution why can't be allowed to start a new execution again? – ironwood Dec 28 '14 at 00:02
  • I'm confused. Are you saying there is no reference or there is no object? Has it released the memory portion that the object was refer? When invoking again it gives java.lang.IllegalThreadStateException not a NullPointer kind of one. I really appreciate your explanation. But I want to clear this. – ironwood Dec 28 '14 at 00:15
  • 4
    Whether an underlying thread has ended, if you have a reference to its corresponding `Thread` object, it will not be GC'ed. Your edit is wrong. – Sotirios Delimanolis Dec 28 '14 at 00:27
  • 1
    Good answer, but it somewhat obscures the difference between a `Thread` object, and the thread that it manages. Once the noob understands that a `Thread` is not a thread, then it's easy to explain that the library only lets you use the `Thread` one time because the thread can only exist one time. – Solomon Slow Dec 28 '14 at 18:43
  • @ James : OK james! can you explain to noob that why thread can only exist one time? Here we have many facts but I'm looking an answer / explanation for WHY? @Sotirios : Yes, that's what I also said. The reference is still there. So, how is it garbage collected? when I print the getStatus also it prints it as TERMINATED. – ironwood Dec 29 '14 at 05:46