How exactly does Java's garbage collection handle threads?
To clarify, I have a peer to peer network I'm writing in Java, and if a peer is determined to be acting maliciously or is rejected from the routing tables, I remove all references to the Peer object, which extends a thread.
Would I be correct in assuming that even though I deleted all references to the instance, the thread for that instance, and therefore the instance, would not be removed by the garbage collector?
No. It will not be collected or stopped while it is running.
You should stop your thread from within the thread, for example by using using the command return;.
Here is an experiment:
public class Main {
public static void main(String[] args) {
Runnable r = new Runnable(){
public void run() {
for (int i=0; i < 10; i++) {
System.out.println("Thread is running");
}
return;
}
};
Thread t=new Thread(r);
t.start();
t=null;
System.out.println("App finished");
}
}
Here is the result:
App finished
Thread is running
Thread is running
Thread is running
Thread is running
Thread is running
Thread is running
Thread is running
Thread is running
Thread is running
Thread is running
So, the thread was not stopped or collected even after the main thread set the reference to null and stopped working.
Related
I created my own thread class implementing the Runnable interface. But every time I start running my own thread class as a new thread, the main class thread does not terminate anymore by itself. Is this just an issue within Eclipse or would I also have problem running this on a Server? Do I have to change something calling the thread so that the main method can terminate properly?
Here's my basic self-made thread:
public class OwnThread implements Runnable {
#Override
public void run() {
//do something
}
}
Here's the main class that won't terminate anymore:
public static void main(String[] args) {
Thread thread = new Thread(new OwnThread());
thread.start();
}
When I debug it, the last called method is the exit()-method of the Thread-class. After going through these lines of code, the process goes on forever:
/**
* This method is called by the system to give a Thread
* a chance to clean up before it actually exits.
*/
private void exit() {
if (group != null) {
group.threadTerminated(this);
group = null;
}
/* Aggressively null out all reference fields: see bug 4006245 */
target = null;
/* Speed the release of some of these resources */
threadLocals = null;
inheritableThreadLocals = null;
inheritedAccessControlContext = null;
blocker = null;
uncaughtExceptionHandler = null;
}
Here's a screenshot of the thread that is running forever. The TestInterface class is where the main-method is located:
But every time I start running my own thread class as a new thread, the main class thread does not terminate anymore by itself.
This is somewhat wrong. Your program does not terminate because there exists at least one non-daemon thread that still is running. The rule is: A Java program is terminated if all non-daemon threads are terminated.
I modified your program to make this behavior clear:
public class OwnThread implements Runnable {
#Override
public void run() {
runForever();
}
public static void main(String[] args) {
Thread thread = new Thread(new OwnThread());
thread.start();
runForever();
}
private static void runForever() {
while (true) {}
}
}
Running that will create two threads that will run forever. One is the main thread which is started by running the program, and the other is the thread started inside the main method:
Modifying the above code by removing the call to runForever in the main method ...
public static void main(String[] args) {
Thread thread = new Thread(new OwnThread());
thread.start();
}
... will result in a different thread picture:
Here the main thread is gone because it is terminated. But the other started thread is still running.
Side note: Suddenly another thread appears - DestroyJavaVM. Have a look at the post DestroyJavaVM thread ALWAYS running for more information.
The issue is indeed not caused by the multithreading logic itself, it is caused by Eclipse and the respective JVM. Running the exact same code in Netbeans or on an Tomcat 8 Server did not lead to any problems. A reinstallation of Eclipse did not solve the malfunction within the Eclipse framework, but having the certainty that the issue does not cause any trouble on a server is sufficient for me to close the case.
Thanks to Seelenvirtuose for the hints and his effort.
Code:
public class ThreadTest {
public static void main(String[] args) {
MyImlementThread mit = new MyImlementThread();
Thread t = new Thread(mit);
t.start();
t = new Thread(mit);
t.start();
}
}
// MyImlementThread
class MyImlementThread implements Runnable {
public void run() {
System.out.println("This is implemented run() method");
}
}
/*
Output
This is implemented run() method
This is implemented run() method
*/
What happens here is the main thread starts two threads and exits. Each of the new threads writes a message to stdout, then ends. At that point since all the non-daemon threads have finished the JVM exits.
The posted code is confusing on account of it defining a Runnable but giving it a name ending in Thread.
A Thread object relates to an os-level thread, calling start on a Thread makes the code in the run method of the passed-in Runnable execute run on a separate thread from the one that called start.
The Runnable defines a task but doesn't specify how it runs. It could be passed into a specific Thread's constructor or submitted to an Executor or run by the current thread.
In this case the Runnable declared has no state, no instance variables are declared. Here two threads can execute the same Runnable without a conflict because there is no shared state. The printstream that writes to the console is synchronized, so the lines written by the threads each get written one at a time and don't get jumbled together.
In the below code, why does the main thread wait until the child thread is finished.
Driver.java
public class Driver {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(new ThreadRunner());
t.start();
}
}
ThreadRunner.java
public class ThreadRunner implements Runnable {
#Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("Child thread" + i);
}
}
}
Here in the Driver class after calling 't.start()' shouldn't the program quit? I'm not using join but still the main thread waits until the newly spun 'ThreadRunner' run is running. Is it because in java the main thread (which is started by main method) always waits until all the threads are shut?
The main thread exits immediately after having started the other thread, but the Java program as a whole continues running as long as there are non-daemon threads alive (and unless you specifically request it, new threads will be non-daemon).
Making the thread a daemon thread is easy: simply call t.setDaemon(true); before starting it.
The main thread doesn't actually wait. The main thread completes. The program does not quit because you create a Thread that is non-daemon. The JVM will shut down when only daemon threads remain.
you can add 'System.out.println("main thread");' below 't.start()'
then you can see main thread is the first.
I know how the thread join method works, but i have a sample question. Please see the example code below
public class RunnableJob implements Runnable{
#Override
public void run(){
Thread currentThread = Thread.currentThread();
System.out.println("Runnable job is run by" + currentThread.getName());
try{
Thread.sleep(1000);
}
catch(InterruptedException ie){
ie.printStackTrace();
}
}
}
public class ThreadExample{
public static void main(String[] args) throws InterruptedException{
RunnableJob runnableJob = new RunnableJob();
Thread thread1 = new Thread(runnableJob,"T1");
Thread thread2 = new Thread(runnableJob,"T2");
Thread thread3 = new Thread(runnableJob,"T3");
Thread thread4 = new Thread(runnableJob,"T4");
thread1.start();
thread1.join();
thread2.start();
thread2.join();
thread3.start();
thread3.join();
thread4.start();
thread4.join();
Thread thread5 = new Thread(runnableJob,"T5");
Thread thread6 = new Thread(runnableJob,"T6");
Thread thread7 = new Thread(runnableJob,"T7");
Thread thread8 = new Thread(runnableJob,"T8");
thread5.start();
thread6.start();
thread7.start();
thread8.start();
}
}
I know that, T1,T2,T3,T4 will block the main thread, before they complete. But is it possible that before T5,T6,T7,T8 actually start running, the main thread completes and T5..T8, remain in runnable state only. If this is possible, how can i produce the same?
Thanks.
The term you are looking for to answer your question is "daemon" threads. As long as there are non-daemon threads running, the application will not terminate and those threads will be able to run to a terminated state.
In your case, therefore, T5...T8 will run and complete as they are non-daemon threads †.
From the documentation for Thread:
When a Java Virtual Machine starts up, there is usually a single non-daemon thread (which typically calls the method named main of some designated class). The Java Virtual Machine continues to execute threads until either of the following occurs:
•The exit method of class Runtime has been called and the security manager has permitted the exit operation to take place.
•All threads that are not daemon threads have died, either by returning from the call to the run method or by throwing an exception that propagates beyond the run method
† In fact the original single non-daemon thread started by the JVM may enter the terminated state before T5...T8 do. That will not stop T5...T8 running to completion in this case.
Please help me find the reason for Thread leak in the code below. The TestThread does not get garbage collected even after run() has completed (verified from the consoled print statement) and the main method has exited (verified from print statement and profiler tool).
The TestThread, however, gets garbage collected if it is set as a Daemon Thread i.e. t.setDaemon(true). The code below is just a sample code which illustrates the problem in my application. I'm trying to use some pre-existing scheduling class (which was designed by someone else using ScheduledExecutorService). I notice that when I keep scheduling multiple Runnables with the class, the created threads never get garbage collected.
public class ThreadTest {
static void runThreadWithExecutor() {
final String name = "TestThread";
ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor(
new ThreadFactory() {
#Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r, name);
t.setDaemon(false);
return t;
}
});
ses.schedule(new Runnable() {
#Override
public void run() {
System.out.println("entered " + name);
System.out.println("exiting " + name);
}},
2,
TimeUnit.SECONDS);
}
public static void main(String[] args) throws InterruptedException {
System.out.println("entered main");
runThreadWithExecutor();
Thread.sleep(5000);
System.out.println("exiting main");
}
}
This is due to the fact that you are not calling shutdown() on your executor service after you have scheduled your last job:
ses.schedule(...);
// this stops any management threads but existing jobs will still run
ses.shutdown();
I just added the shutdown() call to your code and it exits fine. This is true of all ExecutorServices. Without the shutdown the thread pool continues to wait for more jobs to be submitted and is never GC'd.
See #John's answer below for more details.
#Gray is correct with his assessment I just figure I add the why he is correct. The ExecutorService is a thread-pool which will reuse the threads.
Unlike new Thread(runnable).start(); when the run method completes the thread completes and will then be GC'd. When an Executor Runnable completes the thread will sit there and wait for another runnable task to be submitted and used. So by shutting down you are telling the executor to end all of the Threads in the thread pool.
To answer your last part. Setting it to daemon works only because there are no other (non-daemon) threads running. If your application started some other non daemon thread the Executor thread's will continue. Remember a daemon thread will be killed when only daemon threads are running.