后台线程和finally的邂逅
以前我一直觉得finally里面的代码,是一定会执行了,除非出现拔电源等强制停止程序的情况。
But看一下下面这个例子
import java.util.concurrent.TimeUnit;
class ADaemon implements Runnable {
@Override
public void run() {
try {
System.out.println("ADaemon Starting");
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
System.out.println("Always run?");
}
}
}
public class DaemonsDontRunFinally {
public static void main(String[] args) {
Thread thread = new Thread(new ADaemon());
thread.setDaemon(true);//设置为后台线程
thread.start();
}
}
执行结果
ADaemon Starting
如果将代码中的 thread.setDaemon(true);去掉,执行结果是
ADaemon Starting
Always run?
thread.setDaemon(true);这一句话的效果就是将线程作为后台线程执行。
也就是说如果是在后台线程中,这个finally中的代码就有可能不执行了。
为了更好的说明,我将上面的例子修改了一下,在输出完线程开始之后,在每隔一秒打印一行字,总共5行。在mian中停1秒让main晚点结束
import java.util.concurrent.TimeUnit;
class ADaemon implements Runnable {
@Override
public void run() {
try {
System.out.println("ADaemon Starting");
//在打印完线程启动标志之后再打印一下东西
for (int i = 0; i < 5; i++) {
System.out.println("ADaemon print " + i);
TimeUnit.SECONDS.sleep(1);
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
System.out.println("Always run?");
}
}
}
public class DaemonsDontRunFinally {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new ADaemon());
thread.setDaemon(true);//设置为后台线程
thread.start();
//让main方法停1秒之后再结束
TimeUnit.SECONDS.sleep(1);
}
}
输出结果(不一定每次都是这样)
ADaemon Starting
ADaemon print 0
ADaemon print 1
本来应该打印五个“ADaemon print *”的,结果只打印了两个,给人一种这个后台线程被
突然终止了一样。
其实就是这样,当程序中最后一个非后台线程终止时,后台线程就会被“突然”终止。
所以上面出现输出截断的原因就好解释了
程序中总共两个线程,ADaemon后台线程和main所在的非后台线程
当main()所在线程结束了,后台线程就会被终止
所以打印到了一半就停止了,当然finally都还没有得到执行的机会,便自然不会执行了。
注:我觉得这和finally一定会执行,并不矛盾,因为这是属于程序终止,如果没有这种终止的话finally依然会执行的(如果在main中多sleep一会finally就会执行了)。