java 中的线程分为两种:守护线程(Daemon)和用户线程(User)。

  • 用户线程:我们平时所创建的都是用户线程。
  • 守护线程:为用户线程提供服务。

任何线程都可以设置为守护线程和用户线程,通过方法 Thread.setDaemon(boolean);true 则把该线程设置为守护线程,反之则为用户线程。Thread.setDaemon()必须在 Thread.start()之前调用,否则运行时会抛出异常。

两者的区别:
    唯一的区别是判断虚拟机(JVM)何时离开,Daemon 是为其他线程提供服务,如果全部的 User Thread 已经撤离,Daemon 没有可服务的线程,JVM 撤离。也可以理解为守护线程是 JVM 自动创建的线程(但不一定),用户线程是程序创建的线程;比如 JVM 的垃圾回收线程是一个守护线程,当所有线程已经撤离,不再产生垃圾,守护线程自然就没事可干了,当垃圾回收线程是 Java 虚拟机上仅剩的线程时,Java 虚拟机会自动离开。

写个程序来验证一下:

package com.top.test.mutiTheread;public class DaemonTest {public static void main(String[] args) {System.out.println(Thread.currentThread().getName());System.out.println("main线程是守护线程:" + Thread.currentThread().isDaemon());System.out.println("------------------------------------------");Thread t1 = new Thread(new Runnable() {@Overridepublic void run() {try {while (true) {System.out.println(Thread.currentThread().getName() + "我是守护线程t1");Thread.sleep(500);}} catch (InterruptedException e) {e.printStackTrace();}}});t1.setName("守护线程t1");t1.setDaemon(true);Thread t2 = new Thread(() -> {try {int i = 1;while (i <= 10) {System.out.println(Thread.currentThread().getName() + ":我是用户线程t2---" + i);Thread.sleep(500);i++;}System.out.println(Thread.currentThread().getName() + ":我是用户线程t2---我执行完run方法了");} catch (InterruptedException e) {e.printStackTrace();}});t2.setName("用户线程t2");t1.start();t2.start();Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {@Overridepublic void run() {System.out.println("-------------");System.out.println("Java虚拟机退出啦!");}}));}
}

执行结果:

main
main线程是守护线程:false
------------------------------------------
守护线程t1我是守护线程t1
用户线程t2:我是用户线程t2---1
用户线程t2:我是用户线程t2---2
守护线程t1我是守护线程t1
守护线程t1我是守护线程t1
用户线程t2:我是用户线程t2---3
用户线程t2:我是用户线程t2---4
守护线程t1我是守护线程t1
守护线程t1我是守护线程t1
用户线程t2:我是用户线程t2---5
守护线程t1我是守护线程t1
用户线程t2:我是用户线程t2---6
守护线程t1我是守护线程t1
用户线程t2:我是用户线程t2---7
用户线程t2:我是用户线程t2---8
守护线程t1我是守护线程t1
守护线程t1我是守护线程t1
用户线程t2:我是用户线程t2---9
守护线程t1我是守护线程t1
用户线程t2:我是用户线程t2---10
守护线程t1我是守护线程t1
用户线程t2:我是用户线程t2---我执行完run方法了
-------------
Java虚拟机退出啦!

从执行结果可以看出:

  • Main线程不是守护线程;
  • 用户线程退出后,守护线程退出,随即Java虚拟机退出;

对于Runtime.getRuntime().addShutdownHook()这个方法,我解释一下:这个方法的意思就是在jvm中增加一个关闭的钩子hook(一个线程对象),当jvm关闭的时候,会执行系统中已经设置的所有通过方法addShutdownHook添加的钩子,当系统执行完这些钩子后,jvm才会关闭。所以这些钩子可以在jvm关闭的时候进行内存清理、对象销毁等操作。

可以增加多个钩子,我们可以看下其源码:

public void addShutdownHook(Thread hook) {SecurityManager sm = System.getSecurityManager();if (sm != null) {sm.checkPermission(new RuntimePermission("shutdownHooks"));}ApplicationShutdownHooks.add(hook);
}static synchronized void add(Thread hook) {if(hooks == null)throw new IllegalStateException("Shutdown in progress");if (hook.isAlive())throw new IllegalArgumentException("Hook already running");if (hooks.containsKey(hook))throw new IllegalArgumentException("Hook previously registered");
// 最终添加到hooks对象中,hooks是一个map对象,可以存储多个钩子。hooks.put(hook, hook);
}// hooks 的定义
private static IdentityHashMap<Thread, Thread> hooks;

多线程连载:
Java内存模型-volatile的应用(实例讲解)
synchronized的三种应用方式(实例讲解)
可重入锁-synchronized是可重入锁吗?
大彻大悟synchronized原理,锁的升级
一文弄懂Java的线程池
公平锁和非公平锁-ReentrantLock是如何实现公平、非公平的
一图全面了解Java线程的生命周期

守护线程和用户线程的真正区别(实例讲解)相关推荐

  1. java守护线程和用户线程的区别

    Java中的线程可以分为两类,即用户线程和守护线程.用户线程是为了完成任务,而守护线程主要是为其他线程服务. 守护线程的唯一用途是为其他线程提供服务.守护线程会随时中断,因此不要在守护线程上使用需要释 ...

  2. java守护线程和用户线程

    java守护线程和用户线程 1.Java线程分类 Java分两类线程:1.用户线程 2.守护线程 2.区别 1.JVM在用户线程没有结束前,会一直和守护线程一同运行. 2.如果用户线程全部结束,那么J ...

  3. java守护线程与用户线程_详解Java线程-守护线程与用户线程

    干java 开发这么多年, 之前一直没留意java 进程还区分守护进程和用户进程.守护进程这个概念最早还是在linux系统中接触的,直到近期使用java开发心跳检测功能时,使用Timer时才发现原来j ...

  4. 多线程之守护线程daemonVS用户线程

    线程分为守护线程和用户线程:系统默认的用户线程是主线程: 虚拟机中监控内存,垃圾回收等待,日志管理等都属于守护线程,一般默认不显示在控制台,默认false,虚拟机不用等待守护线程执行完毕:守护线程理论 ...

  5. 操作系统 | 关于进程、线程、用户线程、内核线程

    操作系统 | 关于进程.线程.用户线程.内核线程 一.进程和线程 进程:操作系统分配资源的最小单位 线程:CPU调度的最小单位 每个线程共享进程的代码段 每个线程共享进程的数据段 每个线程共享进程的堆 ...

  6. PHP 必须勾选用户协议,javascript实现用户必须勾选协议实例讲解

    在js中设置用户必须阅读完某项协议 才能勾选登陆或注册 (disabled的使用技巧) 仔细观看两张图片画圈部分是不一样的 当滚轮在上面时下面的表单是不可选中的 第二张在底部表单是可选中的 其中方法为 ...

  7. 内核线程和用户线程(SMP)

    用户级和内核级线程  用户级线程:任何应用程序都可以通过使用线程库设计成多线程程序.线程库是用于用户级线程管理的一个例程句,它包含用于创建和销毁线程的代码.在线程间传递消息和数据的代码.调度线程执行的 ...

  8. linux 线程--内核线程、用户线程实现方法

    Linux上进程分3种,内核线程(或者叫核心进程).用户进程.用户线程 内核线程拥有 进程描述符.PID.进程正文段.核心堆栈 当和用户进程拥有相同的static_prio 时,内核线程有机会得到更多 ...

  9. 运行管理员线程和用户线程小练习

    今天学习C#中线程的知识点,于是动手编些有关线程的小例子,用来理解线程的运行原理,希望能够帮助大家尽快入手 using System; using System.Collections.Generic ...

最新文章

  1. 15、子查询注意事项
  2. C# DataTable转ListModel通用类
  3. python locust 能压测数据库_深入浅出 Locust 实现
  4. 实验四 Windows程序设计
  5. C语言中输入输出fread和fwrite函数的用法
  6. ZeroC ICE源代码中的那些事 - 嵌套类和局部类
  7. ROS笔记(5) ROS架构
  8. 工厂模式在 Calendar 类中的应用
  9. python 映射网络驱动器_用Delphi实现网络驱动器的映射和断开
  10. Python(五):list、tuple
  11. Linux禁用文件可执行权限
  12. arduino秒退解决方法
  13. 2021-07-15-2021年全球10大最佳单板计算机开发板(SBC)(第1-3名)
  14. rainyday.js 下雨效果插件使用方法
  15. 微信小程序-分享页面到微信群或者好友携带分享者身份信息
  16. 学习《可复制的领导力》有感
  17. 狂飙高启兰好飒,你看狂飙了吗?
  18. CSAPP实验1:Data Lab笔记
  19. 玩玩群辉NAS-常用命令行
  20. Ubuntu 阿里源更新 amp;amp; nvidia驱动安装 amp;amp; cuda 安装

热门文章

  1. 嵌入式面试(笔试)笔记2
  2. chrome浏览器抓包工具介绍(2022,12,27)
  3. 已解决:Component should be written as a pure functioneslintreact/prefer-stateless-fun报错
  4. 服务器-epoll之缓冲区
  5. 做大数据可视化分析的软件和工具有哪些?
  6. 黄建宏-redis多机数据库
  7. Linux_CentOS7 的桌面图标怎样变小/变小的方法
  8. three.js重新计算UV
  9. Stapler#攻略
  10. 内存超频trfc_P55平台内存超频实战