daemonthread详解

一、daemonthread概述

daemon thread(守护线程)是一种在后台运行的线程。当所有的非守护线程结束时,守护线程随着JVM一起关闭。一般情况下,守护线程用于执行一些后台任务,比如定期清理垃圾、检查网络连接等。

守护线程可以通过 Thread.setDaemon(true) 来设置线程为守护线程,但是必须在调用 start() 方法启动线程之前设置。

public class DaemonThreadExample extends Thread {

    public void run() {
        if (Thread.currentThread().isDaemon()) {
            System.out.println("This is a daemon thread.");
        } else {
            System.out.println("This is not a daemon thread.");
        }
    }

    public static void main(String[] args) {
        DaemonThreadExample t1 = new DaemonThreadExample();
        DaemonThreadExample t2 = new DaemonThreadExample();
        t1.setDaemon(true); // 设置为守护线程
        t1.start();
        t2.start();
    }
}

二、daemon thread的特点

守护线程有以下特点:

1.守护线程在非守护线程结束时自动结束

当所有的非守护线程结束时,JVM 会检查是否还有守护线程在运行,如果没有,则自动退出。因此,守护线程不应该被用来执行需要确保完成的操作,比如写文件等。

2.守护线程自动被设置为低优先级

当一个线程启动时,它会继承其父线程的优先级。但是,守护线程会被自动设置为低优先级,这意味着它们会被优先调度用于执行回收垃圾等不太重要的任务。

3.守护线程不能持有任何锁

因为守护线程会在非守护线程结束时自动结束,如果它持有锁,那么其他线程就无法再获得该锁,这会造成死锁。

三、如何使用daemonthread

1.线程池中使用

可以在线程池中创建守护线程,这样就可以方便地管理和控制守护线程。

public class DaemonThreadPoolExample {

    public static void main(String[] args) throws InterruptedException {
        ExecutorService executorService = Executors.newCachedThreadPool(new ThreadFactory() {
            @Override
            public Thread newThread(Runnable r) {
                Thread thread = new Thread(r);
                thread.setDaemon(true); // 设置为守护线程
                return thread;
            }
        });

        executorService.submit(() -> {
            while (true) {
                System.out.println("daemon thread is running in the thread pool.");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        Thread.sleep(5000);
        executorService.shutdown();
    }
}

2.后台任务调度

比如定期检查数据库连接池是否满足要求等任务可以使用守护线程来执行。下面的代码演示了如何使用 ScheduledThreadPoolExecutor 定期执行一段后台任务。

public class DaemonScheduledExecutorExample {

    public static void main(String[] args) {
        ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1);
        executor.setRemoveOnCancelPolicy(true); // 守护线程需要设置此属性为true,表示从任务队列中删除已取消的任务

        ScheduledFuture future = executor.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                System.out.println("Background task is running.");
            }
        }, 0, 1, TimeUnit.SECONDS);

        executor.setExecuteExistingDelayedTasksAfterShutdownPolicy(false); // 确保shutdown后不再执行delayed任务

        executor.setKeepAliveTime(10, TimeUnit.SECONDS); // 设置线程空闲超时时间
        executor.allowCoreThreadTimeOut(true); // 允许核心线程超时关闭

        // 等待5秒钟,然后取消任务
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        future.cancel(true);
        executor.shutdown();
    }
}

四、daemonthread使用的注意事项

1.不要将需要确保完成的操作放在守护线程中执行

因为守护线程会随着JVM一起关闭,如果需要确保任务完成,不能使用守护线程。

2.不要在守护线程中使用sleep()方法

因为当JVM退出时,守护线程可能会被强制中断,在sleep()期间中断会抛出InterruptedException异常。

3.不要让守护线程持有任何锁

因为守护线程会在非守护线程结束时自动结束,如果它持有锁,那么其他线程就无法再获得该锁,这会造成死锁。

4.守护线程无法在main方法结束后继续执行

因为当main方法结束时,JVM会尝试停止所有线程。如果所有的非守护线程都结束了,守护线程也会被停止。

5.需要使用内存屏障来同步数据访问

因为守护线程的优先级低,因此在数据访问时很可能会出现并发问题。可以使用内存屏障来同步数据访问,保证代码的正确性。

原创文章,作者:小蓝,如若转载,请注明出处:https://www.506064.com/n/246752.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
小蓝小蓝
上一篇 2024-12-12 13:16
下一篇 2024-12-12 13:16

相关推荐

  • Linux sync详解

    一、sync概述 sync是Linux中一个非常重要的命令,它可以将文件系统缓存中的内容,强制写入磁盘中。在执行sync之前,所有的文件系统更新将不会立即写入磁盘,而是先缓存在内存…

    编程 2025-04-25
  • 神经网络代码详解

    神经网络作为一种人工智能技术,被广泛应用于语音识别、图像识别、自然语言处理等领域。而神经网络的模型编写,离不开代码。本文将从多个方面详细阐述神经网络模型编写的代码技术。 一、神经网…

    编程 2025-04-25
  • Linux修改文件名命令详解

    在Linux系统中,修改文件名是一个很常见的操作。Linux提供了多种方式来修改文件名,这篇文章将介绍Linux修改文件名的详细操作。 一、mv命令 mv命令是Linux下的常用命…

    编程 2025-04-25
  • Python输入输出详解

    一、文件读写 Python中文件的读写操作是必不可少的基本技能之一。读写文件分别使用open()函数中的’r’和’w’参数,读取文件…

    编程 2025-04-25
  • nginx与apache应用开发详解

    一、概述 nginx和apache都是常见的web服务器。nginx是一个高性能的反向代理web服务器,将负载均衡和缓存集成在了一起,可以动静分离。apache是一个可扩展的web…

    编程 2025-04-25
  • MPU6050工作原理详解

    一、什么是MPU6050 MPU6050是一种六轴惯性传感器,能够同时测量加速度和角速度。它由三个传感器组成:一个三轴加速度计和一个三轴陀螺仪。这个组合提供了非常精细的姿态解算,其…

    编程 2025-04-25
  • 详解eclipse设置

    一、安装与基础设置 1、下载eclipse并进行安装。 2、打开eclipse,选择对应的工作空间路径。 File -> Switch Workspace -> [选择…

    编程 2025-04-25
  • C语言贪吃蛇详解

    一、数据结构和算法 C语言贪吃蛇主要运用了以下数据结构和算法: 1. 链表 typedef struct body { int x; int y; struct body *nex…

    编程 2025-04-25
  • Python安装OS库详解

    一、OS简介 OS库是Python标准库的一部分,它提供了跨平台的操作系统功能,使得Python可以进行文件操作、进程管理、环境变量读取等系统级操作。 OS库中包含了大量的文件和目…

    编程 2025-04-25
  • Java BigDecimal 精度详解

    一、基础概念 Java BigDecimal 是一个用于高精度计算的类。普通的 double 或 float 类型只能精确表示有限的数字,而对于需要高精度计算的场景,BigDeci…

    编程 2025-04-25

发表回复

登录后才能评论