Java线程有两类,一类是用户线程,另一类是守护线程。
用户线程:运行在前台,执行具体的任务,程序的主线程、连接网络的子线程等都是用户线程。
守护线程:运行在后台,为其他前台线程服务
特点:一旦所有用户线程都结束运行,守护线程会随JVM一起结束工作
应用:数据库连接池中的检测线程,JVM虚拟机启动后的检测线程
最常见的守护线程:垃圾回收线程
如何设置守护线程
可以通过调用Thread类的setDaemnon(true)方法来设置当前的线程为守护线程
注意事项
setDaemon(true)必须在start()方法之前调用,否则会抛出IllegalThreadStateException异常
在收获线程中产生的新线程也是守护线程
不是所有的任务都可以分配给守护线程来执行,比如读写操作或计算逻辑。
下面展示一个代码示例:创建一个守护线程,不断往文件中写入数据。当主线成由于IO请求阻塞时,守护线程随之结束运行。
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.Scanner;
/**
* @Description:
*/
class DaemonThread implements Runnable{
@Override
public void run() {
System.out.println("进入守护线程"+Thread.currentThread().getName());
try {
writeToFile();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("退出守护线程"+Thread.currentThread().getName());
}
private void writeToFile() throws Exception{
File fineName = new File("d:"+File.separator+"daemon.txt");
OutputStream os = new FileOutputStream(fineName,true);
int count = 0;
while (count<999){
os.write(("\r\nword"+count).getBytes());
System.out.println("守护线程"+Thread.currentThread().getName()+
"向文件中写入了word"+count++);
Thread.sleep(1000);
}
}
}
public class DaemonThreadDemo {
public static void main(String[] args) {
System.out.println("进入主线程"+Thread.currentThread().getName());
DaemonThread daemonThread = new DaemonThread();
Thread thread = new Thread(daemonThread);
// 设置为守护线程
thread.setDaemon(true);
thread.start();
Scanner sc = new Scanner(System.in);
sc.next();
System.out.println("退出主线程"+Thread.currentThread().getName());
}
}
运行结果:
我们应尽可能少的使用守护线程——很少有操作能够在不进行清理的情况下被安全地抛弃。特别是,如果在守护线程中执行可能包含I/O操作的任务,那么将是一种危险的行为。守护线程最好用于执行“内部”任务,例如周期性地内存的缓存中移除逾期的数据。
此外,守护线程通常不能用来替代应用程序管理程序中各个服务的生命周期。