【昕宝爸爸小模块】守护线程、普通线程、两者之间的区别

在这里插入图片描述

➡️博客首页       https://blog.csdn.net/Java_Yangxiaoyuan


       欢迎优秀的你👍点赞、🗂️收藏、加❤️关注哦。


       本文章CSDN首发,欢迎转载,要注明出处哦!


       先感谢优秀的你能认真的看完本文,有问题欢迎评论区交流,都会认真回复!


守护线程、普通线程、两者之间的区别

  • 一、✅典型解析
    • 1.1 ✅什么是守护线程(概念)
    • 1.2 ✅守护线程会阻塞其他线程吗
    • 1.3 ✅守护线程有哪些优缺点
    • 1.4 ✅ 哪些场景下需要使用守护线程
  • 二、✅普通线程
    • 2.1 ✅什么是普通线程(概念)
    • 2.2 ✅如何创建线程
    • 2.3 ✅如何开启线程
    • 2.4 ✅如何终止线程
    • 2.5 ✅线程的同步和通信是什么


一、✅典型解析


在Java中有两类线程: User Thread(用户线程)Daemon Thread(守护线程)。用户线程一般用于执行用户级任务,而守护线程也就是 “ 后台线程 ”,一般用来执行后台任务,守护线程最典型的应用就是GC(垃圾回收器)。


这两种线程其实是没有什么区别的,唯一的区别就是Java虚拟机在所有<用户线程>都结束后就会退出,而不会等<守护线程>执行完


1.1 ✅什么是守护线程(概念)


守护线程(Daemon Thread)是一种在后台提供服务的线程,它在程序运行时在后台提供一种通用服务。守护线程并不属于程序中不可或缺的部分,它的生死与整个进程的运行无关。


守护线程的主要作用是为其他线程提供服务,例如垃圾回收线程就是典型的守护线程。当所有的用户线程都已退出运行时,如果还有守护线程存在,JVM(Java虚拟机)会继续运行直到所有的守护线程也结束。当所有非守护线程结束时,如果没有守护线程存在,程序就会终止。


用户可以通过调用Thread类的 setDaemon(true) 方法将线程设置为守护线程模式,这样该线程就会在后台运行并一直服务其他线程。需要注意的是,守护线程不应该执行重要的操作,因为它的终止是不可控制的。


1.2 ✅守护线程会阻塞其他线程吗


守护线程在主线程退出时候会随主线程一起结束,而不会阻塞主线程的退出。


当我们在Java中创建一个线程时,我们可以通过调用Thread类setDaemon(true)方法将其设置为守护线程。守护线程是在后台运行的,当没有用户线程在运行时,守护线程会自动终止。下面是一个示例。



/**
* @author xinbaobaba
* 如何创建一个守护线程
*/
public class DaemonThreadExample {
    public static void main(String[] args) {
        // 创建一个守护线程
        Thread daemonThread = new Thread(() -> {
            while (true) {
                // 守护线程的逻辑
                System.out.println("Daemon thread is running.");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        daemonThread.setDaemon(true); // 设置守护线程
        daemonThread.start(); // 启动守护线程

        // 主线程逻辑
        System.out.println("Main thread is running.");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Main thread is exiting.");
    }
}

代码解析:创建了一个守护线程和一个主线程。主线程会先运行并输出一条消息,然后休眠5秒钟。而守护线程会一直循环输出消息,直到主线程退出。由于守护线程是后台运行的,所以当主线程退出时,守护线程也会自动终止


1.3 ✅守护线程有哪些优缺点


守护线程的优点:

  1. 守护线程在后台提供通用服务,可以减轻主线程的负担,使其专注于执行主要任务。
  2. 守护线程的创建和销毁成本相对较低,可以提高程序的启动速度和执行效率。
  3. 守护线程可以自动终止,不需要手动管理,减少了程序退出时的资源清理工作。

守护线程缺点:

  1. 守护线程的生命周期依赖于用户线程,如果用户线程全部退出,守护线程也会被终止,可能导致一些资源无法得到正确的清理。
  2. 守护线程不控制资源,这可能导致一些重要的资源在程序退出时仍被占用,影响程序的正确关闭。
  3. 守护线程的执行优先级较低,可能会影响程序的实时性和响应速度。

因此,在使用守护线程时需要注意权衡利弊,根据具体需求选择是否使用以及如何使用


1.4 ✅ 哪些场景下需要使用守护线程


守护线程适用于以下场景


  1. 后台任务:有些任务需要在程序运行的后台执行,而不需要与主线程同步。比如,日志记录、垃圾回收、定时任务等都可以使用守护线程来执行,减少对主线程的干扰。

  2. 定时任务:一些定时任务可以作为守护线程执行,例如定时备份数据库、定时清理临时文件等。

  3. 服务监听:在服务器应用中,可以使用守护线程监听某个端口,等待客户端的连接请求。

  4. 资源管理:守护线程还可以用于资源管理,例如数据库连接池中的线程池管理器可以使用守护线程来监控空闲连接并进行回收。

  5. 程序退出:当所有的非守护线程都结束时,守护线程会自动终止。这在一些特定的应用场景下非常有用,比如服务器端应用,在所有客户端连接都断开后,守护线程可以自动关闭服务。

注意:守护线程并不适合执行需要持续运行的任务,因为它们会在所有用户线程结束后自动退出。在实际开发中,我们可以根据具体需求来合理使用守护线程,提高程序的性能和可靠性


二、✅普通线程


2.1 ✅什么是普通线程(概念)


普通线程是用户创建的一般线程,具有个体性,不具有提供公共服务的性质。通常需要我们在线程的循环语句中手动编写循环结束语句,也即线程运行终止的条件语句。


普通线程与守护线程不同,它在程序运行过程中一直存在,直到程序结束或手动终止。普通线程可以与其他线程并发执行,并在其生命周期内完成特定的任务。


在Java中,可以通过继承Thread类或实现Runnable接口来创建普通线程。普通线程的创建和管理需要更多的资源,因此需要注意线程的启动、同步、通信和异常处理等问题。


总结起来的话,普通线程是用户创建的常规线程,需要手动管理其生命周期,常用于执行需要持续运行的任务或并发操作


2.2 ✅如何创建线程


创建线程的方法主要有两种:继承Thread类和实现Runnable接口。


  1. 继承Thread类:创建一个线程类,继承Thread类,并重写run()方法。在run()方法中编写线程要执行的代码。创建线程对象时调用其构造函数,启动线程时调用start()方法。例如:


/**
* @author xinbaobaba
*/
public class MyThread extends Thread {
    public void run() {
        // 线程执行的代码
    }
}

MyThread thread = new MyThread();
thread.start();

  1. 实现Runnable接口:创建一个实现了Runnable接口的类,实现run()方法,在run()方法中编写线程要执行的代码。创建一个Thread对象,将实现Runnable接口的类的对象作为参数传递给Thread构造函数,调用Thread对象的start()方法启动线程。例如:


/**
* @author xinbaobaba
*/
public class MyRunnable implements Runnable {
    public void run() {
        // 线程执行的代码
    }
}

Thread thread = new Thread(new MyRunnable());
thread.start();

无论使用哪种方法创建线程,都需要调用start()方法启动线程,而不是直接调用run()方法。因为run()方法是普通方法,直接调用会立即执行,不会创建新的线程。而start()方法会启动一个新的线程来执行run()方法中的代码。


2.3 ✅如何开启线程


要开启线程,需要创建一个线程对象并调用其start()方法。


在Java中,可以通过继承Thread类或实现Runnable接口来创建线程。无论使用哪种方法,都需要实现run()方法,并在其中编写线程要执行的代码。


创建线程对象时,可以直接使用Thread类或通过实现Runnable接口的类来创建。然后,调用线程对象的start()方法来启动线程。


例如,以下是一个简单的Java代码示例,演示如何开启线程:



/**
* @author xinbaobaba
*/
public class MyThread extends Thread {
    public void run() {
        // 线程执行的代码
        System.out.println("Thread is running.");
    }
}

public class Main {
    public static void main(String[] args) {
        MyThread thread = new MyThread();
        thread.start(); // 启动线程
    }
}

代码解析:创建了一个继承Thread类的MyThread类,并实现了run()方法。然后,在主函数中创建了一个MyThread对象,并调用其start()方法来启动线程。当线程启动后,它将执行run()方法中的代码,输出“Thread is running.”。


2.4 ✅如何终止线程


终止线程的方法主要有三种

  1. 使用退出标志:在run()方法中设置一个boolean类型的标志,并通过设置这个标志为true或false来控制while循环是否退出。
  2. 使用stop方法:强制终止线程,但这种方法不推荐使用,因为stop和suspend、resume一样,也可能发生不可预料的结果。
  3. 使用interrupt方法:中断线程。可以通过捕获InterruptedException异常来控制线程的退出。

注意,终止线程时应该谨慎处理,避免资源泄漏和数据不一致等问题。在实际开发中,应该根据具体情况选择合适的方法来管理线程的生命周期


在Java中,可以通过设置一个boolean类型的变量作为线程的退出标志,在线程的while循环中不断检查这个标志,如果标志为true,则退出循环并结束线程。以下是一个示例代码:



/**
* @author xinbaobaba
*/
public class MyThread extends Thread {
    private boolean isRunning = true;

    public void run() {
        while (isRunning) {
            // 线程执行的代码
            System.out.println("Thread is running.");
        }
    }

    public void stopThread() {
        isRunning = false;
    }
}

public class Main {
    public static void main(String[] args) {
        MyThread thread = new MyThread();
        thread.start(); // 启动线程

        // 等待一段时间后终止线程
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        thread.stopThread(); // 停止线程
    }
}

代码解析:创建一个继承Thread类的MyThread类,并在其中定义了一个boolean类型的变量isRunning作为线程的退出标志。在run()方法中,我们使用while循环不断检查isRunning变量的值,如果isRunning为true,则执行线程要执行的代码。当需要停止线程时,可以在其他地方调用 stopThread()方法isRunning 设置为false,从而结束while循环并退出线程。


在主函数中,我们创建了一个MyThread对象,并调用其start()方法来启动线程。然后,我们使用 Thread类的sleep()方法 使主线程休眠5秒钟,模拟一段时间后需要停止线程的场景。最后,我们调用thread对象的stopThread()方法来停止线程。需要注意的是,在实际开发中,应该避免使用Thread类的stop()方法来停止线程,因为该方法会强制终止线程,可能导致资源泄漏和数据不一致等问题。


问:线程的三种终止方法,哪一种最常用呢 ?


线程的三种终止方法包括使用退出标志、使用stop方法和使用interrupt方法。其中,最常用的方法是使用interrupt方法


使用 interrupt方法 来终止线程是最常用的方法,因为它提供了一种优雅的方式来通知被停止的线程停止执行。通过调用线程的interrupt方法,可以向线程发送一个中断请求,线程可以选择在适当的时候响应这个请求并停止执行。这种方式的优点在于它不会立即强制停止线程,而是给线程一个机会来清理资源、释放锁等,从而避免出现资源泄漏或其他问题。此外,interrupt方法还提供了一种通用的机制,可以用于处理其他类型的中断请求,如用户界面中的取消操作等。


相比之下,使用退出标志或stop方法来终止线程并不常用。使用退出标志需要在程序中设置一个标志变量,当需要停止线程时将标志变量设置为true,然后等待线程自行停止。这种方式需要线程自行处理停止逻辑,而且可能会造成线程阻塞或死锁等问题。使用stop方法会强制停止线程,可能会导致资源泄漏或其他问题,因此不推荐使用。


综上所述,使用interrupt方法是线程终止最常用的方法,因为它提供了一种优雅、安全的方式来停止线程执行,并可以用于处理其他类型的中断请求。


2.5 ✅线程的同步和通信是什么


线程的同步和通信是实现多线程并发执行的必要机制。


线程同步是指线程之间的协调与合作,以确保它们能够按照正确的顺序执行,避免出现数据不一致或资源冲突的问题。线程同步可以通过互斥锁、条件变量、信号量等机制实现,以确保同一时刻只有一个线程访问共享资源。


线程通信是指线程之间传递数据或消息的机制。由于不同的线程可能执行在不同的处理器或不同的内存空间上,因此需要一种机制来在不同的线程之间传递信息。线程通信可以通过共享内存、消息队列、管道等机制实现,以确保线程之间能够正确地传递数据或状态信息。


线程的同步和通信是多线程编程中的重要概念,用于协调和管理不同线程的执行,以确保程序能够正确地运行并实现预期的功能。


Demo:




/**
* @author xinbaobaba
* 演示了线程同步和通信的基本概念
*/
public class SharedResource {
    private int count = 0;
    private final Object lock = new Object();

    public void increment() {
        synchronized (lock) {
            count++;
        }
    }

    public int getCount() {
        return count;
    }
}

public class MyThread extends Thread {
    private SharedResource resource;

    public MyThread(SharedResource resource) {
        this.resource = resource;
    }

    public void run() {
        for (int i = 0; i < 10; i++) {
            resource.increment();
            System.out.println("Thread " + Thread.currentThread().getId() + " count: " + resource.getCount());
        }
    }
}

public class Main {
    public static void main(String[] args) {
        SharedResource resource = new SharedResource();
        MyThread thread1 = new MyThread(resource);
        MyThread thread2 = new MyThread(resource);
        thread1.start();
        thread2.start();
        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Final count: " + resource.getCount());
    }
}

在上面的代码中,我们定义了一个SharedResource类,其中包含一个共享资源count和一个同步锁lock。increment()方法用于增加count的值,并在访问count时进行同步,以确保线程安全。MyThread类继承了Thread类,并在run()方法中模拟了对共享资源的并发访问。在Main类中,我们创建了两个MyThread对象,并启动它们。使用 join() 方法等待线程执行完成,然后输出最终的count值。


这个示例演示了线程同步的基本概念,通过synchronized关键字对共享资源进行同步访问,确保同一时刻只有一个线程能够修改count 的值。同时,通过线程通信的方式,每个线程在访问完共享资源后输出count的值,以便观察线程的执行顺序和共享资源的状态变化。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/322254.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

创新引领游戏产业:武汉灰京文化的成功之路

随着科技的不断发展&#xff0c;游戏产业已经成为全球最具竞争力和创新性的领域之一。在这个激烈的竞技场上&#xff0c;武汉灰京文化凭借其专业化、创新性和诚信的经营理念迅速崭露头角&#xff0c;成功将自身打造成为游戏产业的巨头。 作为游戏产业的佼佼者&#xff0c;武汉…

【极光系列】Windows安装Mysql8.0版本

【极光系列】Windows安装Mysql8.0版本 一.mysql服务端 下载地址&#xff1a;https://dev.mysql.com/downloads/mysql/ 二.解压二进制包 解压到 E:\mysql-8.0.35-winx64目录下&#xff0c;记住你解压后的目录&#xff0c;后续要使用三.创建my.ini文件 tips&#xff1a;mys…

【数据结构和算法】删除链表的中间节点

其他系列文章导航 Java基础合集数据结构与算法合集 设计模式合集 多线程合集 分布式合集 ES合集 文章目录 其他系列文章导航 文章目录 前言 一、题目描述 二、题解 三、代码 四、复杂度分析 前言 这是力扣的1657题&#xff0c;难度为中等&#xff0c;解题方案有很多种&…

unity C#什么是线程锁,以及使用案例

文章目录 原理1. **互斥**&#xff08;Mutual Exclusion&#xff09;:2. **缓存一致性与内存屏障**&#xff1a;3. **操作系统的支持**&#xff1a;4. **编程语言级别的实现**&#xff1a;5. **避免死锁**&#xff1a;图示 实例1实例2 原理 线程锁的原理主要是为了在多线程环境…

FastAdmin西陆教育系统(xiluEdu)开源代码

应用介绍 一款基于FastAdminThinkPHPUniapp开发的西陆教育系统&#xff08;微信小程序、移动端H5、安卓APP、IOS-APP&#xff09;&#xff0c;以下是教育系统所包含的一些功能&#xff1a; 视频课程&#xff1a;教育系统提供在线视频课程&#xff0c;学生可以通过网络观看教师…

双双入选 中科驭数第二代DPU芯片K2和低时延DPU卡荣获2023年北京市新技术新产品新服务认定

北京市新技术新产品&#xff08;服务&#xff09;认定是北京市从重点发展的先导技术、战略性新兴产业和现代服务业领域中&#xff0c;选拔出技术先进、产权明晰、质量可靠、市场前景广阔&#xff0c;且符合构建“高精尖”经济结构要求的产品及服务&#xff0c;具有较高权威性和…

C盘满了,我用什么思路清理?

20240115 上周六同事传了一个很大的虚拟机给我&#xff0c;C盘就红了 虽然是飞秋选错了存储文件的路径&#xff0c;但后来忘了&#xff0c;就开始毫无目的删除文件&#xff0c;过程中会有没有权限删除的&#xff0c;这样还是没有改善。 咨询了公司IT技术人员&#xff0c; 告…

conda环境下No module named ‘pytorch_lightning‘问题解决

1 问题描述 在训练wav2lip模型时&#xff0c;出现如下错误&#xff1a; D:\.conda\wav2lip\python.exe D:/ml/wav2lip384/parallel_syncnet_tanh.py --data_root D:/ml/Wav2Lip/data/25fps_out/ --checkpoint_dir syncnet_checkpoints/ --checkpoint_path Traceback (most re…

Java学习(十七)--IO流

File类 介绍 文件是保存数据的地方&#xff0c;而文件在程序中是以流的形式来操作&#xff1b; java.io.File类是 java.io 包中唯一代表磁盘文件本身的对象&#xff1b; 如果希望在程序中操作文件和目录&#xff0c;则都可以通过 File 类来完成 file能新建、删除、重命名…

2、HarmonyOS系统架构

一、HarmonyOS系统采用分层架构 1、整体系统功能按照&#xff1a; “系统>子系统>功能/模块”逐级展开。 在多设备部署场景下&#xff0c;支持根据实际需求裁剪某些非必要的子系统或功能/模块。 2、内核子系统&#xff1a; HarmonyOS采用多内核设计&#xff0c;支持针…

鸿蒙系统ArkTs语法入门

鸿蒙系统ArkTs的ts语法入门 前言1. 变量声明2. 数据类型2.1 基本数据类型2.2 复杂数据类型2.3 联合类型2.4 空类型和未定义类型 3. 函数3.1 匿名函数和箭头函数 4. 类和接口类的访问权限接口类的继承内部类 7. 结构体参考材料 前言 每个语言都有控制流语句就不写测试代码了。 …

用通俗易懂的方式讲解:使用 LangChain 和 LlamaIndex 从零构建PDF聊天机器人

随着大型语言模型&#xff08;LLM&#xff09;&#xff08;如ChatGPT和GPT-4&#xff09;的兴起&#xff0c;现在比以往任何时候都更容易搭建智能聊天机器人&#xff0c;并且可以堆积如山的文档&#xff0c;为你的输入提供更准确的响应。 无论你是想构建个人助理、定制聊天机器…

手把手教你学会接口自动化系列十三-将所有的crm用例由json改为excel

本篇汇总我写接口自动化用到的所有excel数据如下&#xff1a; 登录模块 添加线索模块 添加场景模块

Java调用openai微调Fine-tuning实战示例

注: 建议先看微调文档, 遵从官网给出的规则。例如: jsonl训练文件至少有10个例子, 否则报错 官网微调文档https://platform.openai.com/docs/guides/fine-tuning官网微调APIhttps://platform.openai.com/docs/api-reference/fine-tuning 1. 实现步骤 1. 准备好jsonl数据集2…

three.js设置模型边界线

three.js设置模型边界线 图例 步骤 拿到模型&#xff08;如果是外部模型需要遍历&#xff09;&#xff0c;设置透明度根据模型的几何体创建EdgesGeometry几何体创建线条材质创建LineSegments线模型模型加入线模型 代码 const m model.scene.getObjectByName("仓库&qu…

第 3 章 稀疏数组和队列

文章目录 3.1 稀疏 sparsearray 数组3.1.1 先看一个实际的需求3.1.2 基本介绍3.1.3 应用实例3.1.4 课后练习 3.2 队列3.2.1 队列的一个使用场景3.2.2 队列介绍3.2.3 数组模拟队列思路3.2.4 数组模拟环形队列 3.1 稀疏 sparsearray 数组 3.1.1 先看一个实际的需求  编写的五…

众和策略:券商又念“紧箍咒” 绕标套现的头疼了

又有券商对两融事务念“紧箍咒”。 近来&#xff0c;记者从广发证券获悉&#xff0c;该公司已发布《关于调整融资融券负债归还规矩的告诉》&#xff0c;自2024年1月15日起&#xff0c;决议禁止融资买入证券用于归还融券负债。 相关业内人士以为&#xff0c;自上一年10月融资融…

【数据结构 】哈夫曼编译码器

数据结构-----哈夫曼编译码器 题目题目描述基本要求算法分析 代码实现初始化编码解码打印代码打印哈夫曼树 总结 题目 题目描述 利用哈夫曼编码进行信息通信可大大提高信道利用率&#xff0c;缩短信息传输时间&#xff0c;降低传输成本。 要求&#xff1a;在发送端通过一个编…

DC电源模块与AC电源模块的对比分析

DC电源模块与AC电源模块的对比分析 BOSHIDA DC电源模块和AC电源模块是两种常见的电源模块&#xff0c;它们在供电方式、稳定性、适用范围等方面有所不同&#xff0c;下面是它们的对比分析&#xff1a; 1. 供电方式&#xff1a; DC电源模块通过直流电源供电&#xff0c;通常使用…