守护线程和普通线程的区别

两种线程

一般情况下,不做特殊说明配置,默认是用户线程

用户线程(User Thread)

是系统工作线程,它会完成这个程序需要完成的业务操作。

守护线程(Deamon Thread)

是一种比较特殊的线程为其他的线程服务,在后台默认的完成一些系统服务,比如垃圾回收线程就是一个典型的例子。

守护线程作为一个服务线程,没有服务对象就没有必要继续运行了,如果守护线程全部结束了,意味着程序需要完成的任务已经结束了,系统就可以退出了。所以假如系统只剩下守护线程的时候,Java 虚拟机会自动退出。

设置守护线程

线程的 daemon 属性

  1. Thread 的 daemon 默认值为 false 表示是用户线程
  1. 设置守护线程后,如果用户线程执行完毕后,JVM 进程退出。例子如下:
java 复制代码
package io.pipi;

import java.util.concurrent.TimeUnit;

public class Main {
    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + "\t 开始初始化"
                    + (Thread.currentThread().isDaemon() ? "守护线程" : "用户线程"));
            while (true) {

            }
        }, "t1");
        t1.setDaemon(true);
        t1.start();

        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        System.out.println(Thread.currentThread().getName() + "\t  ---end 主线程");

    }
}

如果设置 t1.setDaemon(true); 后台线程,当线程执行完毕过后退出

JVM 源码

  1. jvm 中使用 Threads 类跟踪正在运行的线程
cpp 复制代码
class Threads: AllStatic {
    	friend class VMStructs;
    private:
        static int         _number_of_threads; //系统中正在运行的线程
        static int         _number_of_non_daemon_threads; //非守护线程数
    
    public:
    
    	static void destroy_vm();  //main 方法结束后回调
}
  1. Threads::destroy_vm 方法会在 main 方法结束后调用
cpp 复制代码
void Threads::destroy_vm() {
  JavaThread* thread = JavaThread::current();

  // Wait until we are the last non-daemon thread to execute, or
  // if we are a daemon then wait until the last non-daemon thread has
  // executed.
  bool daemon = java_lang_Thread::is_daemon(thread->threadObj());
  int expected = daemon ? 0 : 1;
  //等待最后一个非守护线程退出
  {
    MonitorLocker nu(Threads_lock);
    while (Threads::number_of_non_daemon_threads() > expected)
      // This wait should make safepoint checks, wait without a timeout.
      nu.wait(0);
  }


  // 执行 shutdown hook
  // run Java level shutdown hooks
  thread->invoke_shutdown_hooks();

  // 其他资源释放操作
}

所以我们从 jvm 源码中可以看到,守护线程不会影响 jvm 的退出,也验证Thread.java 中的描述。 机器翻译如下(更加方便佐证结论):

总结

  • 如果用户线程全部结束意味着程序需要完成的任务已经结束了,守护线程随着 JVM 一同工作
  • setDaemon(true) 必须在 start() 之前设置,否则会报 java.lang.IllegalThreadStateException 异常
相关推荐
架构技术专栏4 小时前
Agent 工具调用:从工具声明到执行反馈
前端·人工智能·后端
别动我齐刘海4 小时前
C++ 工程化学习
java·linux·前端·c++·学习·机器学习·机器人
码事漫谈4 小时前
你让AI干的活,它可能只干了十分之一——而你根本看不出来
后端
Wx-bishekaifayuan4 小时前
express皖美特色农产品网售系统53118-计算机课程设计、毕业设计
人工智能·spring boot·后端·python·课程设计·express·旅游
Wx-bishekaifayuan5 小时前
springboot汉中旅游服务平台41442-计算机课程设计、毕业设计
spring boot·后端·python·django·课程设计·express·旅游
code2cat5 小时前
Java进阶篇之AtomicLongFieldUpdater:把累计额度留在对象字段中
java·cas·并发编程
WeiXin_DZbishe5 小时前
基于springboot城市公交实时运营与调度系统-计算机毕设 附源码【课程设计】66173
java·vue.js·spring boot·后端·python·php·课程设计
泡茶喝茶写代码5 小时前
A股量化数据工程:从 REST 接口到策略信号(第 18 篇):放量缩量异动扫描
java·python·股票数据api·股票数据api接口·股票api数据接口·股票量化数据api·股票量化数据接口
WeiXin_DZbishe6 小时前
基于Springboot+AI的kuall音乐广场的设计与实现-计算机毕设 附源码【课程设计】12715
vue.js·人工智能·spring boot·后端·python·php·课程设计