Java用户线程和守护线程

  今天看Java一个关于多线程返回值方式的示例,发现一个自己不太能理解的问题,就是在主线程中启动了几个工作线程,主线程中也没有join,工作线程居然也是正常输出了回调的结果。这个跟linux C++下的线程知识可是不一样的,在C++下,如果main函数退出了,那么所有的子线程也就退出了,我一开始怀疑是不是书上写的不够仔细,没有测试,所以自己写了几个类简单的测试了一下。代码如下:

  ThreadCallback.java代码:

package thread.callback;

public class ThreadCallback {
    public void callBack(String msg) {
        System.out.println(msg);
    }
}

  WorkThread.java代码:

package thread.callback;

public class WorkThread extends Thread{
    private ThreadCallback callback;
    private String threadName;
    public WorkThread(ThreadCallback _callback, String _threadName) {
        // TODO Auto-generated constructor stub
        this.callback = _callback;
        this.threadName = _threadName;
    }
        
    @Override
    public void run() {
        // TODO Auto-generated method stub
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        this.callback.callBack(this.threadName);
    } 
}

  test.java代码:

package thread.callback;

public class test {
    public static void main(String[] args) {
        for (int i=0; i<5; ++i) {
            ThreadCallback callback = new ThreadCallback();
            WorkThread workThread = new WorkThread(callback, "thread" + Integer.toString(i));
            workThread.start();
            
        }
        
        System.out.println("to be end");
    }
}

  代码非常简单啊,就是WorkThread中简单回调Callback中的接口,然后再callback中打印一下,运行的结果如下:

to be end
thread0
thread2
thread3
thread1
thread4

  从输出结果(thread输出顺序,每次不一定一样)可以看出来,主线程退出之后,其创建的几个子线程还是在正常运行的,直到输出了指定的结果。那么也就是跟之前linux C++下的主从线程关系不太一样了。经过搜索,发现Java线程有一个是否为守护线程的属性,默认情况下这个属性是不设置的,为false,代表这个线程是一个用户线程,如果使用Thread的setDaemon接口设置一下,那么线程属性就会变成守护线程。

  用户线程不会随着主线程退出而结束,而是会继续在JVM中运行的,直到自身结束,JVM也会等所有用户线程都执行完毕才退出。

  而守护线程会在所有用户线程(包括主线程)退出之后,一起退出,这时候JVM也就退出了。

  我们把test.java改成这样:

package thread.callback;

public class test {
	public static void main(String[] args) {
		for (int i=0; i<5; ++i) {
			ThreadCallback callback = new ThreadCallback();
			WorkThread workThread = new WorkThread(callback, "thread" + Integer.toString(i));
			workThread.setDaemon(true);
			workThread.start();
			
		}
		
		System.out.println("to be end");
	}
}

  新增setDaemon,在thread运行之前设置,然后运行程序,程序只打印"to be end"然后就退出了。

  如果我们将5个子线程中的4个设置为守护线程,一个为用户线程,会怎样呢?

  test.java代码

package thread.callback;

public class test {
	public static void main(String[] args) {
		for (int i=0; i<5; ++i) {
			ThreadCallback callback = new ThreadCallback();
			WorkThread workThread = new WorkThread(callback, "thread" + Integer.toString(i));
			if (i != 4)
				workThread.setDaemon(true);
			workThread.start();
			
		}
		
		System.out.println("to be end");
	}
}

  那么也会可能输出所有线程结果。为啥说可能呢,这要看唯一的用户线程thread4啥时候退出了,它一退出,那么其他守护进程不管有没有执行完,都会被迫退出。在我们上面的例子中比较难出现,因为thread4是最后一个启动的,而且大家都做相同简单的事情,如果把thread4改成thread1,那么就非常容易测试出来了。

  比如我们把WorkThread.java的run改成这样:

public void run() {
        // TODO Auto-generated method stub
        try {
            if (threadName.equals("thread4"))
                Thread.sleep(1000);
            else
                Thread.sleep(3000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        this.callback.callBack(this.threadName);
    } 

  那么输出结果就是:

to be end
thread4

  可以从上面的运行结果中看出用户线程和守护线程的区别了!

原文地址:https://www.cnblogs.com/chobits/p/5139860.html