优雅的停止
在Thread类中,提供用于使线程停止或挂起的方法全部因为可能会导致线程死锁的原因被弃用了,所以停止一个线程,我们不能采取直接调用相应的方法来暴力实现了。我们需要采取一种比较优雅的方法来实现线程的结束。
public class JavaDome {
public static boolean flag = true;
public static void main(String[] args) {
new Thread(() -> {
int count = 0;
while (flag) {
try {
Thread.sleep(50); //每50毫秒运行一次
} catch (InterruptedException ignored) {}
System.out.println("第" + count++ + "次循环");
}
}).start();
//主线程休眠300毫秒,即让上面的那个线程执行300毫秒之后执行主线程
try {
Thread.sleep(300);
} catch (InterruptedException ignored) {}
//主线程的任务:将flag修改为false
flag = false;
}
}
后台守护线程
在Java中线程有用户线程和守护线程两类。
守护线程是一种运行在后台的线程服务线程,当用户线程在执行时,守护线程也可以同时存在;但当用户线程结束时,守护线程也会消失。
这就可以用一个保镖的例子来类比。一个人请了一个保镖。那么当这个人活着的时候,这个保镖会一直在他身边执行保护他的任务,而当这个人死掉了,那么这个保镖的任务也就到此结束。
关于守护线程有如下方法:
- public final void setDaemon(boolean on) 将此线程标记为daemon线程或用户线程。
- public final boolean isDaemon() 判断这个线程是否是守护线程。
当我们没有使用守护线程时:
public class JavaDome {
public static void main(String[] args) {
Thread user = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(100);
} catch (InterruptedException ignored) {}
System.out.println("【用户线程的第" + i + "次循环】");
}
}
});
Thread daemon = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(100);
} catch (InterruptedException ignored) {}
System.out.println("守护线程的第" + i + "次循环");
}
}
});
user.start();
daemon.start();
}
}
随机抽取的一个执行结果:
显然在用户线程结束之后守护线程依然在继续执行。
在所有线程启动之前,添加语句daemon.setDaemon(true);
之后,随机抽取一次执行结果:
显然守护线程和用户线程执行的次数是一样的,即运行的时间相同。
在Java中,最大的守护线程是GC(即GarbageCollector)。任意一个Java程序的运行,GC都会作为守护线程参与其中,进行垃圾回收,以提高程序运行效率。