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
可以从上面的运行结果中看出用户线程和守护线程的区别了!