Java中的守护线程问题

目录
  • 守护线程
    • 在Java中有两类线程
  • 守护线程与用户线程的区别
    • 1 定义和概述
    • 2 使用守护线程
    • 3 测试案例
    • 4 注意事项

守护线程

在Java中有两类线程

  • User Thread(用户线程)
  • Daemon Thread(守护线程)

守护线程的功能非常简单,在其本身是一个线程的同时,主要是为了给其他的线程提供服务,比如说计时器,清空高速缓存等等操作,守护线程具有和被守护线程一样的生命周期(这里并不是说守护线程和被守护线程常常是1-1的关系),当被守护线程死亡,守护线程往往也会死亡,当虚拟机中只剩下守护线程时,虚拟机就会退出,因为此时也没有运行程序的必要了

一个比较通俗的解释:任何一个守护线程都是整个JVM中所有非守护线程的保姆

只要当前JVM实例中尚存在任何一个非守护线程没有结束,守护线程就全部工作;只有当最后一个非守护线程结束时,守护线程随着JVM一同结束工作。

守护线程的作用是为其他线程的运行提供便利服务,守护线程最典型的应用就是 GC (垃圾回收器),它就是一个很称职的守护者。

需要注意的点是:

  • 守护线程的优先级比较低
  • 守护线程要注意考虑关机动作
  • 守护线程应该永远不去访问固有资源,比如说文件或者数据库,因为它会在任何时候甚至一个操作的中间发生中断。

不要给守护线程分担读写逻辑或者计算逻辑,因为无法确定守护线程是否已经完成了工作,但是只要User退出守护线程也会立马结束,对于计算机程序来说这样的程序可能多次运行结果不一样,很显然这对于程序来说是毁灭性的。

操作:

通过thread.setDaemon(true) 将线程转换为守护线程

这个方法必须在thread.start()之前进行调用

守护线程与用户线程的区别

介绍Java守护线程与用户线程的概念和使用方法,以及相关注意事项。

1 定义和概述

Java 中的线程分为两类,分别为daemon 线程(守护线程〉和user 线程(用户线程)。守护线程又称Daemon线程,运行在后台,看不见;用户线程运行在前台,看的见。

在JVM启动时会调用main 函数, main 函数所在的线程就是一个用户线程,其实在JVM内部同时-还启动了好多守护线程, 比如垃圾回收线程。

Daemon线程是一种支持型线程,因为它主要被用作程序中后台调度以及支持性工作。这意味着,当一个Java虚拟机中不存在非Daemon线程的时候,Java虚拟机将会退出,而不管当前是否有守护线程,也就是说守护线程是否结束并不影响JVM的退出。

实际上,在main线程运行结束后,JVM会自动启动一个叫作DestroyJavaVM 的线程,该线程会等待所有用户线程结束后终止JVM 进程。

在Tomcat的NIO实现NioEndpoint中会开启一组接受线程来接受用户的连接请求,以及一组处理线程负责具体处理用户请求,在默认情况下,接受线程和处理线程都是守护线程,这意味着当tomcat 收到shutdown 命令后并且没有其他用户线程存在的情况下tomcat 进程会马上消亡,而不会等待处理线程处理完当前的请求。

2 使用守护线程

在线程start之前,可以通过调用thread.setDaemon(true)将线程设置为Daemon线程。

守护线程有两种结束方式:

  • 守护线程也具有自己的run();方法,当后台线程完成自己的run方法后,守护线程结束。
  • 用户线程运行结束,守护线程自动结束。

3 测试案例

public class Daemon {
//启动该类,将会构造两条线程,main线程和一条子线程。
    public static void main(String[] args) throws InterruptedException {
        //测试非守护线程
        //可以看到,输出"main线程结束"之后,子线程还在继续输出,程序没有结束
//        test1();
        //测试守护线程
        //可以看到,输出"main线程结束"之后,子线程没有继续输出,程序结束
        test2();
    }

    /**
     * 测试非守护线程
     *
     * @throws InterruptedException
     */
    public static void test1() throws InterruptedException {
        Thread thread = new Thread(() -> {
            while (true) {
                try {
                    Thread.currentThread().sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("子线程非守护线程");
            }
        });
        thread.start();
        Thread.currentThread().sleep(1000);
        System.out.println("main线程结束");
    }

    //测试守护线程
    public static void test2() throws InterruptedException {
        Thread thread = new Thread(() -> {
            while (true) {
                try {
                    Thread.currentThread().sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("子线程守护线程");
            }
        });
        thread.setDaemon(true);
        thread.start();
        Thread.currentThread().sleep(1000);
        System.out.println("main线程结束");
    }
}

使用jps查看java进程,可以发现如果子线程是守护线程那么主线程结束,子线程也结束了;如果子线程不是守护线程那么主线程结束,子线程没有结束。

4 注意事项

Daemon线程被用作完成支持性工作,但是在Java虚拟机退出时Daemon线程中的finally块并不一定会执行,如下代码:

public class Daemon {
    public static void main(String[] args) {
        Thread thread = new Thread(new DaemonRunner(), "DaemonRunner");
        thread.setDaemon(true);
        thread.start();
    }

    static class DaemonRunner implements Runnable {
        @Override
        public void run() {
            try {
                SleepUtils.second(10);
            } finally {
                System.out.println("DaemonThread finally run.");
            }
        }
    }
}

运行Daemon程序,可以看到在控制台上没有任何输出。main线程(非Daemon线程)在启动了线程DaemonRunner之后随着main方法执行完毕而终止,而此时Java虚拟机中已经没有非Daemon线程,虚拟机需要退出。Java虚拟机中的所有Daemon线程都需要立即终止,因此DaemonRunner立即终止,但是DaemonRunner中的finally块并没有执行。

在构建Daemon线程时,不能依靠finally块中的内容来确保执行关闭或清理资源的逻辑。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • 谈谈Java中的守护线程与普通线程

    守护线程与普通线程的唯一区别是:当JVM中所有的线程都是守护线程的时候,JVM就可以退出了:如果还有一个或以上的非守护线程则不会退出.(以上是针对正常退出,调用System.exit则必定会退出) 所以setDeamon(true)的唯一意义就是告诉JVM不需要等待它退出,让JVM喜欢什么退出就退出吧,不用管它. 守护线程在没有用户线程可服务时自动离开,在Java中比较特殊的线程是被称为守护(Daemon)线程的低级别线程.这个线程具有最低的优先级,用于为系统中的其它对象和线程提供服务.将一个用

  • Java 语言守护线程 Daemon Thread使用示例详解

    目录 守护线程 用户线程设为守护线程 守护线程 在Java语言中有两类线程:用户线程和守护线程.我们通俗的讲,任意一个守护线程都是整个JVM中所有线程的"大管家":只要当前Java虚拟机中还有任意一个非守护线程没有结束,它们的守护线程就不能结束,要持续工作:只有当最后一个非守护线程结束时,守护线程才随着Java虚拟机一起结束工作. 其作用就是为其他线程的运行提供服务,就像是一个护道者,保证其他线程的顺利运行 用户线程设为守护线程 我们将用户线程设为守护线程的办法就是Thread类的se

  • Java中守护线程介绍及使用

    目录 一.什么是守护线程 二.为什么需要守护线程 三.如何使用 注意: 总结 一.什么是守护线程 在说守护线程之前,我们先说一下什么是用户线程. 用户线程:我们平常创建的普通线程.守护线程(即 Daemon thread):是个服务线程,用来服务于用户线程:不需要上层逻辑介入,当然我们也可以手动创建一个守护线程.在JVM中,所有非守护线程都执行完毕后,无论有没有守护线程,虚拟机都会自动退出. 二.为什么需要守护线程 存在任意一个用户线程的时候,JVM就不会退出.那么JVM 程序在什么情况下能够正

  • Java中用户线程与守护线程的使用区别

    目录 1.默认用户线程 2.主动修改为守护线程 2.1 设置线程为守护线程 2.2 设置线程池为守护线程 3.守护线程 VS 用户线程 3.1 用户线程 3.2 守护线程 3.3 小结 4.守护线程注意事项 4.1 setDaemon 执行顺序 4.2 守护线程的子线程 4.3 join 与守护线程 5.守护线程应用场景 6.守护线程的执行优先级 7.总结 前言; 在 Java 语言中线程分为两类:用户线程和守护线程,而二者之间的区别却鲜有人知,所以本文磊哥带你来看二者之间的区别,以及守护线程需

  • Java守护线程和用户线程的区别

    目录 守护线程定义 创建守护线程 将线程池设置为守护线程 守护线程 VS 用户线程 用户线程 守护线程 守护线程注意事项 总结 前言: 在 Java 语言中,线程分为两类:用户线程和守护线程,默认情况下我们创建的线程或线程池都是用户线程,所以用户线程也被称之为普通线程. 想要查看线程到底是用户线程还是守护线程,可以通过 Thread.isDaemon() 方法来判断,如果返回的结果是 true 则为守护线程,反之则为用户线程. 我们来测试一下默认情况下线程和线程池属于哪种线程类型?测试代码如下:

  • java高并发的用户线程和守护线程详解

    目录 程序只有守护线程时,系统会自动退出 设置守护线程,需要在start()方法之前进行 线程daemon的默认值 总结 守护线程是一种特殊的线程,在后台默默地完成一些系统性的服务,比如垃圾回收线程.JIT线程都是守护线程.与之对应的是用户线程,用户线程可以理解为是系统的工作线程,它会完成这个程序需要完成的业务操作.如果用户线程全部结束了,意味着程序需要完成的业务操作已经结束了,系统可以退出了.所以当系统只剩下守护进程的时候,java虚拟机会自动退出. java线程分为用户线程和守护线程,线程的

  • Java中的守护线程问题

    目录 守护线程 在Java中有两类线程 守护线程与用户线程的区别 1 定义和概述 2 使用守护线程 3 测试案例 4 注意事项 守护线程 在Java中有两类线程 User Thread(用户线程) Daemon Thread(守护线程) 守护线程的功能非常简单,在其本身是一个线程的同时,主要是为了给其他的线程提供服务,比如说计时器,清空高速缓存等等操作,守护线程具有和被守护线程一样的生命周期(这里并不是说守护线程和被守护线程常常是1-1的关系),当被守护线程死亡,守护线程往往也会死亡,当虚拟机中

  • Java语言多线程终止中的守护线程实例

    Java中线程分为两种类型:用户线程和守护(服务)线程.通过Thread.setDaemon(false)设置为用户线程;通过Thread.setDaemon(true)设置为守护线程;不设置则默认为用户线程. 结束单线程用 Thread.interrupt() 方法,多线程结束则需要设置守护线程.当不存在用户线程时,守护线程就会全部终结(可以理解为:守护线程是服务线程,用户线程是被服务线程,用户线程(被服务线程)全都没有了,服务线程便没有存在意义而自动终结) 例子: class StopThr

  • java中进程与线程_三种实现方式总结(必看篇)

    一:进程与线程 概述:几乎任何的操作系统都支持运行多个任务,通常一个任务就是一个程序,而一个程序就是一个进程.当一个进程运行时,内部可能包括多个顺序执行流,每个顺序执行流就是一个线程. 进程:进程是指处于运行过程中的程序,并且具有一定的独立功能.进程是系统进行资源分配和调度的一个单位.当程序进入内存运行时,即为进程. 进程的三个特点: 1:独立性:进程是系统中独立存在的实体,它可以独立拥有资源,每一个进程都有自己独立的地址空间,没有进程本身的运行,用户进程不可以直接访问其他进程的地址空间. 2:

  • Java中四种线程池的使用示例详解

    在什么情况下使用线程池? 1.单个任务处理的时间比较短 2.将需处理的任务的数量大 使用线程池的好处: 1.减少在创建和销毁线程上所花的时间以及系统资源的开销 2.如不使用线程池,有可能造成系统创建大量线程而导致消耗完系统内存以及"过度切换". 本文详细的给大家介绍了关于Java中四种线程池的使用,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍: FixedThreadPool 由Executors的newFixedThreadPool方法创建.它是一种线程数量固定的线程

  • 对python 多线程中的守护线程与join的用法详解

    多线程:在同一个时间做多件事 守护线程:如果在程序中将子线程设置为守护线程,则该子线程会在主线程结束时自动退出,设置方式为thread.setDaemon(True),要在thread.start()之前设置,默认是false的,也就是主线程结束时,子线程依然在执行. thread.join():在子线程完成运行之前,该子线程的父线程(一般就是主线程)将一直存在,也就是被阻塞 实例: #!/usr/bin/python # encoding: utf-8 import threading fro

  • java中多线程与线程池的基本使用方法

    目录 前言 继承Thread 实现Runnale接口 Callable 线程池 常见的4种线程池. 总结 前言 在java中,如果每个请求到达就创建一个新线程,开销是相当大的.在实际使用中,服务器在创建和销毁线程上花费的时间和消耗的系统资源都相当大,甚至可能要比在处理实际的用户请求的时间和资源要多的多.除了创建和销毁线程的开销之外,活动的线程也需要消耗系统资源.如果在一个jvm里创建太多的线程,可能会使系统由于过度消耗内存或"切换过度"而导致系统资源不足.为了防止资源不足,服务器应用程

  • Java中Map实现线程安全的3种方式

    目录 方式1. 使用Hashtable 方式2. 使用Collections.synchronizedMap(newHashtable()) 方式3. 使用ConcurrentHashMap 方式1.  使用Hashtable Map<String,Object> hashtable=new Hashtable<String,Object>(); 这是所有人最先想到的,那为什么它是线程安全的?那就看看它的源码,我们可以看出我们常用的put,get,containsKey等方法都是同

  • Java中如何判断线程池任务已执行完成

    目录 不判断的问题 方法1:isTerminated 缺点分析 扩展:线程池的所有状态 方法2:getCompletedTaskCount 方法说明 优缺点分析 方法3:CountDownLatch 优缺点分析 方法4:CyclicBarrier 方法说明 优缺点分析 总结 前言: 很多场景下,我们需要等待线程池的所有任务都执行完,然后再进行下一步操作.对于线程 Thread 来说,很好实现,加一个 join 方法就解决了,然而对于线程池的判断就比较麻烦了. 我们本文提供 4 种判断线程池任务是

  • 【java 多线程】守护线程与非守护线程的详解

    Java中有两类线程:User Thread(用户线程).Daemon Thread(守护线程) 用户线程即运行在前台的线程,而守护线程是运行在后台的线程. 守护线程作用是为其他前台线程的运行提供便利服务,而且仅在普通.非守护线程仍然运行时才需要,比如垃圾回收线程就是一个守护线程.当VM检测仅剩一个守护线程,而用户线程都已经退出运行时,VM就会退出,因为没有如果没有了被守护这,也就没有继续运行程序的必要了.如果有非守护线程仍然存活,VM就不会退出. 守护线程并非只有虚拟机内部提供,用户在编写程序

随机推荐