Java Multithreading: Behaviour when Reference count of thread object becomes zero - java

[Before I begin I tried searching related questions, since I found none, I ask a question here]
I am learning Java, and the following scenario hit my head:
class MyThread extends Thread {
void run(){
//a heavy function
}
}
And now in the main thread, I invoke this thread as:
public static void main(...){
new MyThread().start();
System.gc(); //just a request..
//end of main thread too.
//Reference to that MyThread object is now zero.
}
I ran that code. It seems the thread is still alive. The program ends when all the threads quit.
My questions:
When the reference count is zero, wont the thread be eligible for GC? If it is really eligible, what is the behaviour of garbage collection? Will the thread be terminated?
I know its a bad thing to do but is it well defined to not have otherThread.join() in main()?
I have a few explanation of myself (but I do not know how right I am -- the reason I made a post here):
JVM maitains a reference to the thread as long as it is active. So ref count is never really zero.
The executing function has an implicit this reference, so the ref count is again not zero.
Am I correct in any of the explanations above? Or is there any other explanation altogether?
Thanks and regards :)

Each running thread constitutes a root for the GC. Any object reachable from one of the roots is not eligible for GC, and the thread has a thread-local reference to the java.lang.Thread instance (returned by Thread.currentThread()). So no, your thread won't be GCed until it ends running, since the Thread instance is reachable from the running thread.
I don't see why it would be a bad thing not to call join() on the spawned thread. If you don't care when the spawned thread ends, you don't need to join it. The application will stop when the last non-daemon thread stops running.
Also, note that the number of references is not what is used by the GC to tell if an object is eligible for GC or not. Graphs of objects which maintain references to each other (a DOM tree for example) can be eligible for GC, if the graph is not reachable anymore.

1. JVM will terminate only when all the Non-Daemon thread including the Main thread has terminated. (Main thread not the main() method).
2. A Thread will die immediately as it has finished running its run() method, But as you will be knowing that, every thread (toe, ie thread of execution) is associated with the Instance of the Thread class.
3. So when the thread die, it moves in to the dead state (i am not mentioning the thread pool here) , But the object of Thread class which was associated with the thread is still there, but has permanently lost its threadness.
4. But there is a high chance that your thread is still running only the main method has finished.
5. Calling join() is not at all bad, but should be used with caution.

When the reference count is zero, wont the thread be eligible for GC?
No. A thread becomes eligible for GC when it terminates and there are no references.
If it is really eligible, what is the behaviour of garbage collection? Will the thread be terminated?
See above.
I know its a bad thing to do but is it well defined to not have otherThread.join() in main()?
It isn't a bad thing to do, and it is perfectly well-defined: the JVM will exit when all the non-daemon threads have exited.
JVM maitains a reference to the thread as long as it is active. So ref count is never really zero.
Correct.
The executing function has an implicit this reference, so the ref count is again not zero.
Incorrect. Consider static methods. The executing function is executing in an active thread, by definition, so the thread is active, by definition, so it can't be GC'd. Your thinking here is rather circular.

Related

In java, does a Thread keep going even if nothing can access it?

So, you've got a java class ExampleThread that extends Thread. To make this example simple, let's say that its run() method simply sleep()s for 10 seconds and then prints "Hello World" to the screen. However, it gets created like so:
public void startThread() {
//Create local variable
ExampleThread example = new ExampleThread();
example.start();
}
If we call this method and then the main thread goes on to do other things, will the Hello World get printed or not? Most Java objects cease to exist the moment nothing can refer to them (and nothing can refer to 'example', seeing as it was a local variable). Are running threads different?
Sorry if this has already been asked, I couldn't find anything about it.
Most Java objects cease to exist the moment nothing can refer to them...
For all practical purposes, that is true, but in reality, there may be an interval of time before the garbage collector reclaims the object.
...and nothing can refer to 'example', seeing as it was a local variable
There's your mistake.
First of all, example is not the Thread object. example is a variable that refers to the Thread object. example exists in the activation record for your startThread() call, and it ceases to exist as soon as startThread() returns, but the Thread object exists on the heap. And,...
...There is another reference to it that is not visible in your program.
The Thread object is not a thread. It is merely a proxy for the actual operating system thread that was created when you called example.start(). Before example.start() returns, it has created a new operating system thread including the stack for that thread. Somewhere on the stack for the new thread, below the call to the run() method, there is a call to a private method with a local variable that refers to the Thread object.
That hidden local variable is what keeps the Thread from being garbage collected until after run() has returned. Every thread in a Java program has a hidden reference to its own Thread object.
Even if you don't hold a reference to that thread, it still is referenced internally by the ThreadGroup. Otherwise you'd be right that the thread would be expected to be destroyed by the Garbage Collector. So no special handling here, but a non-so-obvious reason.
The daemon attribute - as mentioned in the comments - has nothing to do here. If only daemon threads are left, the Java Virtual Machine is shutting down but both types of threads are handled in the same way.

What happen if we want to interrupt the thread by setting the current by substituting equal to null [duplicate]

After a thread started, if the reference of the thread is set to null, what will happen to the thread? Does it stop? Is it eligible for GC?
Like this:
t.start();
t = null;
Live thread will continue running even its reference is set to null.
Just like any other object, when there are no references to it, it is eligible to GC. The tricky point is that a running thread has a reference in a ThreadGroup even if your program does not retain one, thus a running thread is never GCed.
what will happen to the thread?
Nothing.
Does it stop?
No.
Is it eligible for GC?
No.
No, setting the reference to null will not effect the thread, other than it has one less reference pointing at it. And yes, any object with active references pointing at it will not be garbage collected. If you want the thread to be eligible for GC (and more importantly stop doing stuff) then interrupt what it is doing:
someThread.interrupt();
from the Oracle docs:
An interrupt is an indication to a thread that it should stop what it
is doing and do something else. It's up to the programmer to decide
exactly how a thread responds to an interrupt, but it is very common
for the thread to terminate
The thread will be running, its reference is just set to null and thats why it will not be eligible for GC.

Java "unstopped " executed/finished threads

I've got a question about threads. When I do sth like this:
new Thread(new Runnable(){
#Override
public void run() {
//sth to do
}
}).start();
What happens when all the code in run() is executed ? Does the system automatically deletes the thread or does the thread still remain in memory?
thx & regards
When a thread finished its run() method, it will enter the 'dead' state. Then the next thread in your stack runs after.
Dead state :
"A thread is considered dead when its run() method completes. It may
still be a viable Thread object, but it is no longer a separate thread
of execution. Once a thread is dead, it can never be brought back to
life! (The whole "I see dead threads" thing.) If you invoke start() on
a dead Thread instance, you'll get a runtime (not compiler) exception.
And it probably doesn't take a rocket scientist to tell you that if a
thread is dead, it is no longer considered to be alive."
Java's Threading Model is a little bit more complicated than that.
Basically, a java.lang.Thread is just a wrapper around some data, not a process by itself. When you call the .start() method, a native thread is created and linked to your java Thread. This work is done by the JVM using internal data structures (JavaThread and OSThread).
Once the .run() method finish, many operations are performed by the JVM to delete the native thread that was used. Therefore, you won't see this thread anymore in you process list (using top or ps, for example).
However, the objects that were allocated in the heap and the java.lang.Thread instance itself stay in memory until a GC cycle collects them.
So, to sum up :
Yes, the JVM deletes the native thread that was used
No, the JVM does not delete the java.lang.Thread instance that was used
The GC will eventually collect this instance
For more information, you should read the book "Java Performance" by Charlie Hunt. It contains lots of information on this topic (and many others).
Hope that helps !
When the code in a thread finishes executing, the thread is stopped.
The Thread instance will still exist until it gets GC'd, but the actual system thread will no longer exist.
If you don't use any custom-configured thread pool mechanism, your thread will die and the Threadobject itself will be eligible to garbage collection.

is there any way to confirm if the thread is killed at the end of execution?

is there any way to confirm if the thread is killed at the end of execution? If the garbage collector takes long time to destroy the threads even when they are available for GC, out of memory exceptions may arise. to get rid of those kind of issues, it would be good to know if the threads have been destroyed.
As of now, my understanding is that at the end of run method , the thread gets killed and we need not do anything explicitly to kill the thread instance.
Thanks in advance!
class A
{
public static void main()
{
Thread t = new Thread(new TestA());
t.start();
Thread t1 = new Thread(new TestB());
t1.start();
Thread t2 = new Thread(new TestC());
t2.start();
}
}
class TestA implements Runnable {
Thread t;
public void run() {
for(...){
try{
}catch()
{
....
}
}
}
}
You are absolutely right that "at the end of run method, the thread gets killed and we need not do anything explicitly to kill the thread instance". Simply letting the thread leave its run() method normally is enough.
If you want to make sure that a particular thread has terminated, then Thread.isAlive() will check, and Thread.join() will wait until it happens. If you have a particular set of threads that you're worried about, then keep a reference to them somewhere, and check up on them using these methods.
Thread.getAllStackTraces()
gets you a current map of threads/stacktraces. However I would normally expect the JVM to clear up the threads upon exit from run(). Obviously if you're using some sort of thread pooling then that's not the case.
You can use some softwares like visualvm to monitor the thread states .
These kind of softwares will give you full flexibility to profile your application in a visual way.
To check the state of a thread , you can call the getState() method on a thread object to see the state of the thread.
The javadoc of OutOfMemoryError says:
Thrown when the Java Virtual Machine cannot allocate an object because
it is out of memory, and no more memory could be made available by the
garbage collector.
So, if a thread is not running anymore and is eligible to GC, the GC will try to collect it before throwing an OOM. Like with any other object.
is there any way to confirm if the thread is killed at the end of execution?
There's no sense confirming something you know to be true. Whenever the JVM process dies, all its threads are automatically killed by the operating system. Any other behavior is a bug in the OS.
If the garbage collector takes long time to destroy the threads even when they are available for GC, out of memory exceptions may arise.
The garbage collector doesn't kill threads - the JVM wraps operating-system-specific thread libraries into a consistent Java-language thread abstraction, so those thread libraries determine when a thread dies.
my understanding is that at the end of run method, the thread gets killed and we need not do anything explicitly to kill the thread instance.
That is correct.
If you look up in the javadoc for the Thread class you will see many methods that might help you check what you want, for example:
activeCount() : Returns the number of active threads in the current thread's thread group.
You can use this as a debug method.
isAlive() : Tests if this thread is alive.
To check if a specific thread is alive.
join() : Waits for this thread to die.
If you call this at the end of your method then it will wait for the thread to join (i.e. to end execution) before advancing. If you call for all threads, then you are sure that all have finished when the main() has finished.
destroy() : Destroys this thread, without any cleanup.
Does what it says, but I would never suggest this.
Hope it helps!

Will setting the only reference to null mean it and its child threads are garbage collected?

I have an application which has to live as a service, I create an object which then spawns off a buch of threads.
If I set the only reference to that object to null will all the child threads get cleaned up? or will I suffer from a memory leak.
Do I have to explicitly terminate all the child threads?
Threads and static references are 'root objects'. They are immune from GCing and anything that can be traced back to them directly or indirectly cannot be collected. Threads will therefore not be collected as long as they are running. Once the run method exits though, the GC can eat up any unreferenced thread objects.
Yes, you need to make sure your other threads stop. The garbage collector is irrelevant to this. You should also do so in an orderly fashion though - don't just abort them.
Here's a pattern in C# for terminating threads co-operatively - it's easy to translate to Java.
As others have mentioned, threads won't be cleaned up until they've been stopped. They are root objects for the GC, so you don't have to keep references to them. Your application won't quit until all threads have exited.
There is one exception to this rule. If you mark a thread as a daemon then it will not prevent your application from exiting, and if there are no other non-daemon threads running they it will be cleaned up automatically.
See the javadoc for Thread for more info.
No matter the theory (or StackOverflow answers), you should also create some test to see if what you intended to do, is really happening. Maybe you have some forgotten pointer preventing garbage collection.

Categories