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

news2024/11/16 19:46:53

在这里插入图片描述

➡️博客首页       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的值,以便观察线程的执行顺序和共享资源的状态变化。


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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

打造完美跨境商城源码,助你轻松进军国际市场

随着全球化的深入&#xff0c;跨境电商已成为各国企业拓展国际市场的重要途径之一。根据最新数据显示&#xff0c;跨境电商市场规模逐年扩大&#xff0c;预计未来几年将保持较高增长率。因此&#xff0c;拥有一套完善的跨境商城源码成为企业进军国际市场的关键。 跨境商城源码…

Java--ListUtil工具类,实现将一个大列表,拆分成指定长度的子列表

文章目录 前言实现代码执行结果 前言 在项目中有时会出现列表很大&#xff0c;无法一次性批量操作&#xff0c;我们需要将列表分成指定大小的几个子列表&#xff0c;一份一份进行操作&#xff0c;本文提供这样的工具类实现这个需求。 实现代码 以下为ListUtil工具类代码实现…

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

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

Java 树形结构数据生成导出excel文件V2

** >> 相对于V1版本&#xff0c;优化了代码逻辑&#xff0c;合理使用递归计算树数据的坐标 << ** 1、效果 2、使用方法 import com.alibaba.fastjson.JSONArray; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.usermodel.Workboo…

[HTML]Web前端开发技术12(HTML5、CSS3、JavaScript )——喵喵画网页

希望你开心&#xff0c;希望你健康&#xff0c;希望你幸福&#xff0c;希望你点赞&#xff01; 最后的最后&#xff0c;关注喵&#xff0c;关注喵&#xff0c;关注喵&#xff0c;佬佬会看到更多有趣的博客哦&#xff01;&#xff01;&#xff01; 喵喵喵&#xff0c;你对我真的…

多商户入驻系统APP源码系统:功能强大+分销+秒杀+拼团+砍价+优惠券+完整的安装代码包以及搭建教程

科技的不断发展&#xff0c;互联网在不断的进步&#xff0c;传统的商业形态正在逐步向数字化转型。在这个大背景下&#xff0c;多商户入驻系统APP源码系统应运而生&#xff0c;旨在为各类商家提供一个功能强大的线上商业平台&#xff0c;以提升其市场竞争力。该系统集成了丰富的…

Linux:NTP校时、PTP校时

目录 前言一、NTP校时1、简介2、ubuntu使用 NTP3、嵌入式设备使用 NTP 校时4、NTP 服务器的校时精度 二、PTP校时1、简介2、ubuntu使用 PTP3、嵌入式设备使用 PTP 校时 三、PTP 校时和 NTP 校时那个精度高一些 前言 在进行网络协议通信时&#xff0c;我们有时候需要计算通信的延…

【面试合集】说说提高微信小程序的应用速度的手段有哪些?

面试官&#xff1a;说说提高微信小程序的应用速度的手段有哪些&#xff1f; 一、是什么 小程序启动会常常遇到如下图场景&#xff1a; 这是因为&#xff0c;小程序首次启动前&#xff0c;微信会在小程序启动前为小程序准备好通用的运行环境&#xff0c;如运行中的线程和一些基…

Spring集成

目录 概述1 声朋一个简单的集成流1.1 使用XML定义集成流1.2 使用Java配置集成流1.3 使用Spring lntegration 的 DSL 配置 2 Spring integration 功能概览2.1 消息通道2.2 过滤器2.3 转换器2.4 路由器2.5 切分器2.6 服务激活器2.7 网关2.8 通道适配器2.9 端点模块 概述 就像我们…

图像识别与计算机视觉有什么区别?

图像识别和计算机视觉在很多方面存在差异&#xff0c;这些差异主要体现在以下几个方面&#xff1a; 1. 研究范围 图像识别是计算机视觉领域的一个子集。计算机视觉不仅包括图像识别&#xff0c;还涵盖了更广泛的内容&#xff0c;如场景理解、目标跟踪、分割、识别和解释等。简而…

说清楚Kubernetes、Docker、Dockershim、Containerd、runC、CRI、OCI的关系

Kubernetes v1.20版本 的 release note 里说 deprecated docker。并且在后续版本 v1.24 正式删除了 dockershim 组件&#xff0c;这对我们有什么影响呢&#xff1f;Kubernetes 1.20: The Raddest Release | Kubernetes 为了搞明白这件事情&#xff0c;以及理解一系列容器名词 …

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

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

Java里解压zip和rar包

zip的解压提供了一种方法&#xff0c; rar的解压提供了两种方法&#xff0c;第一种方法是调用命令调用主机安装的解压缩工具&#xff0c; 第二种方法&#xff0c;需要注意一下&#xff0c;需要导一个包 <dependency><groupId>com.github.junrar</groupId>&l…

NR C-DRX inactivity Timer的工作原理

drx-inactivityTimer 是C-DRX中比较关键的一个timer&#xff0c;这里是其工作流程的总结。 inactivity-timer是UE等待成功解码PDCCH的持续时间&#xff0c;从PDCCH的最后一次成功解码开启&#xff0c;timer超时后UE可以返回sleep。 UE 应在一次成功解码PDCCH 后重新启动inactiv…

优优嗨聚集团:债务逾期,如何应对与解决?

在现代社会&#xff0c;债务问题已成为越来越多人面临的难题。债务逾期不仅会给个人带来巨大的经济压力&#xff0c;还会影响个人信用记录&#xff0c;甚至可能引发法律纠纷。那么&#xff0c;当债务逾期时&#xff0c;我们应该如何应对与解决呢&#xff1f; 一、了解债务情况 …

数据库——DAY1(Linux上安装MySQL8.0.35(网络仓库安装))

一、环境部署 1、Red Hat Enterprise Linux 9.3 64 位 2、删除之前安装过本地镜像版本的MySQL软件&#xff08;以前未安装过&#xff0c;请跳过此步骤&#xff09; [rootlocalhost ~]# dnf remove mysql-server -y [rootlocalhost ~]# rm -rf /var/lib/mysql [rootlocalhost …

带你了解烧结钕铁硼的成型工艺

与传统的粉末冶金工艺相比&#xff0c;钕铁硼的成型具有磁场取向和氧化防护这两大特点&#xff0c;成型过程基本决定了磁体的几何形状、尺寸和取向度&#xff0c;是烧结钕铁硼制备的关键环节&#xff0c;成型一般分为干压和湿压两大类。 图片来源&#xff1a;曹帅&#xff0c;烧…

梦回2004!我用全志V3s做了个成本100元,功能媲美MP4的随身终端

本项目是基于全志V3S的随身终端&#xff08;类似MP4&#xff09;&#xff0c;命名为V3S-PI&#xff0c;开发板使用四层板制作&#xff0c;全板采用0603电容电阻&#xff0c;相较于0402&#xff0c;制作更为方便&#xff0c;同时成本可压缩至100以内。 项目简介 开发板选用全志…

Linux多网卡绑定实现负载均衡详解

将多块网卡绑定同一IP地址对外提供服务&#xff0c;可以实现高可用或者负载均衡。直接给两块网卡设置同一IP地址是不可以的。通过 bonding&#xff0c;虚拟一块网卡对外提供连接&#xff0c;物理网卡的被修改为相同的MAC地址。 目录 1、bond的作用 2、Bonding聚合链路工作模…

pyqt5 pyinstaller 打包 QThread QLable QscrollArea 滑动 红果短剧

废话 不多说&#xff0c;直接上代码&#xff01;&#xff01;&#xff01; UI.py self.scrollArea QtWidgets.QScrollArea(self.centralwidget)self.scrollArea.setGeometry(QtCore.QRect(20, 130, 541, 511))self.scrollArea.setWidgetResizable(True)self.scrollArea.setOb…