Java中的守护线程和非守护线程

Java中的线程分为用户线程和守护线程。守护线程在所有非守护线程结束后随JVM一同终止,常用于提供后台服务,如垃圾回收。线程通过setDaemon(true)方法在启动前设为守护线程。在守护线程中产生的新线程同样是守护线程。Timer创建的线程默认是非守护线程,修改为守护线程后,当所有用户线程结束,JVM会随之退出。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Java中有两类线程: User Thread(用户线程) Daemon Thread(守护线程) 

守护线程也叫后台线程, 指的是程序在运行的时候后台提供一种通用服务的线程, 比如jvm中垃圾回收线程, 这种线程并不属于程序中不可或缺的部分. 因此当所有非守护线程结束时, 程序也就终止了, 同时会杀死进程中所有的守护线程. 反过来说, 只要有任何非守护线程在运行, 程序就不会终止.

守护线程和非守护线程的区别就是jvm的离开, 如果用户线程已经全部退出运行了, 只剩下守护线程存在了, 虚拟机也就退出了. 因为没有了被守护者, 守护线程也就没工作可做了, 也就没有继续运行程序的必要了.

将线程转换为守护线程可以通过调用Thread对象的setDaemon(true)方法来实现. 在使用守护线程时需要注意: 

  • thread.setDaemon(true)必须在thread.start()之前设置, 否则会抛出一个IllegalThreadStateException异常, 你不能把正在运行的常规线程设置为守护线程
  • 在Daemon线程中产生的新线程也是Daemon的
  • 守护线程应该永远不去访问固有资源, 如文件, 数据库, 因为它会在任何时候甚至在一个操作的中间发生中断.
  • Timer代码: 
import java.util.Date;
import java.util.TimerTask;
public class MyTask extends TimerTask
{
  @Override
  public void run() {
    System.out.println("任务执行了,时间为:"+new Date());
}

主函数

import java.util.Calendar;
import java.util.Date;
import java.util.Timer;

public class Test1 {
public static void main(String[] args){
    System.out.println("当前时间:"+new Date());
    Calendar calendar=Calendar.getInstance();
    calendar.add(Calendar.SECOND,10);
    Date date=calendar.getTime();
    MyTask task=new MyTask();
    Timer timer=new Timer();
    timer.schedule(task,date);
   }
}

运行结果: 

当前时间为: Mon Jun 17 20:12:37 CST 2019
任务执行了, 时间为Mon Jun 17 20:12:47 CST 2019

任务虽然运行完了, 但进程还未销毁, 呈红色状态, 为什么会出现这种情况呢?

让我们看看Timer的源码

public Timer() {
    this("Timer-" + serialNumber());
}
public Timer(String name) {
    thread.setName(name);
    thread.start();
}

可以看出每创建一个Timer就是启动一个新的线程, 那么启动的线程不是守护线程, 所以一直运行. 将新创建的Timer改成守护线程, 更改如上的代码

import java.util.Calendar;
import java.util.Date;
import java.util.Timer;
public class Test1 {
public static void main(String[] args){
    System.out.println("当前时间:"+new Date());
    Calendar calendar=Calendar.getInstance();
    calendar.add(Calendar.SECOND,10);
    Date date=calendar.getTime();
    MyTask task=new MyTask();
    Timer timer=new Timer(true);
    timer.schedule(task,date);
 }
}

运行结果如下

当前时间为: Mon Jun 17 20:12:42 CST 2019

守护线程中产生的线程也就是守护线程

public class Daemon implements Runnable {
    private Thread[] t = new Thread[10];

    @Override
    public void run() {
        for (int i = 0; i < t.length; i++) {
            t[i] = new Thread(new DaemonSpawn());
            t[i].start();
            System.out.println("DaemonSpawn " + i + " started.");
        }
        for (int i = 0; i < t.length; i++) {
            System.out.println("t[" + i + "].isDaemon() = " +
                    t[i].isDaemon() + ".");
        }
        while (true) {
            Thread.yield();
        }
    }
}

类DaemonSpawn:

public class DaemonSpawn implements Runnable {
    @Override
    public void run() {
        while (true) {
            Thread.yield();
        }
    }
}

主函数:

import java.util.concurrent.TimeUnit;
public class Test1 {
    public static void main(String[] args) throws InterruptedException {
    Thread d = new Thread(new Daemon());

    d.setDaemon(true); //必须在启动线程前调用

    d.start();

    System.out.println("d.isDaemon() = " + d.isDaemon() + ".");

    TimeUnit.SECONDS.sleep(1);
    }
}

运行结果:

 

d.isDaemon() = true.
DaemonSpawn 0 started.
DaemonSpawn 1 started.
DaemonSpawn 2 started.
DaemonSpawn 3 started.
DaemonSpawn 4 started.
DaemonSpawn 5 started.
DaemonSpawn 6 started.
DaemonSpawn 7 started.
DaemonSpawn 8 started.
DaemonSpawn 9 started.
t[0].isDaemon() = true.
t[1].isDaemon() = true.
t[2].isDaemon() = true.
t[3].isDaemon() = true.
t[4].isDaemon() = true.
t[5].isDaemon() = true.
t[6].isDaemon() = true.
t[7].isDaemon() = true.
t[8].isDaemon() = true.
t[9].isDaemon() = true.

Process finished with exit code 0

如果将main函数中的TimerUnit.SECONDS.sleep(1)注释掉, 看一下它的源码: 

public void sleep(long timeout) throws InterruptedException {
    if (timeout > 0) {
        long ms = toMillis(timeout);
        int ns = excessNanos(timeout, ms);
        Thread.sleep(ms, ns);
    }
}

其实就是对Thread.sleep()的封装, 提供了可读性更好的线程暂停操作, 注释后代码运行结果如下: 

d.isDaemon() = true.
DaemonSpawn 0 started.
DaemonSpawn 1 started.
DaemonSpawn 2 started.
DaemonSpawn 3 started.
DaemonSpawn 4 started.
DaemonSpawn 5 started.
DaemonSpawn 6 started.
DaemonSpawn 7 started.
DaemonSpawn 8 started.
DaemonSpawn 9 started.

说明了如果用户线程全部退出了, 只剩下守护线程存在了, 虚拟机也就退出了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值