面试官: 有了解过线程组和线程优先级吗

别再为调试发愁!STM32CubeMX+FreeRTOS下,串口printf打印的保姆级配置指南(基于STM32F429) 本文详细介绍了在STM32CubeMXFreeRTOS环境下实现稳定串口printf打印的配置方法。通过硬件选型、基础配置、线程安全的重定向实现以及高级调试技巧,帮助开发者解决多任务环境下的串口输出问题,提升调试效率。特别适用于STM32F429开发板用户。 阅读详情

前言

目前正在出一个Java多线程专题长期系列教程,从入门到进阶含源码解读, 篇幅会较多, 喜欢的话,给个关注

什么是线程组

在Java中,线程组使用ThreadGroup表示,其中Thread存于线程组中,从字面意思也很好理解。在创建线程过程中,Thread不能独立于线程组之外,之前我们学习创建线程时,没有指定线程组,因为在默认情况下,它会将当前的线程环境作为线程组, 可以通过Thread.currentThread().getThreadGroup()获取线程组,线程组可以方便管理我们的线程,一定程度上提高了安全性

public class ThreadGroupTest {
    public static void main(String[] args) {
        new Thread(() -> {
            System.out.println(Thread.currentThread().getThreadGroup().getName());
        }).start();
        System.out.println(Thread.currentThread().getThreadGroup().getName());
    }
}

输出:

main
main

可以发现在main线程组下

ThreadGroup是一个标准的「向下引用」的树状结构,这样设计的原因是「防止"上级"线程被"下级"线程引用而无法有效地被GC回收」

线程优先级

线程的优先级级别由操作系统决定,不同的操作系统级别是不一样的,在Java中,提供了一个级别范围1~10,方便我们去参考。Java默认的线程优先级为5,线程的执行顺序由调度程序来决定,线程的优先级会在线程被调用之前设定。

源码描述:

  /**
     * 最低级别
     */
    public final static int MIN_PRIORITY = 1;

   /**
     * 默认级别
     */
    public final static int NORM_PRIORITY = 5;

    /**
     * 最高级别
     */
    public final static int MAX_PRIORITY = 10;

获取线程优先级别

 public static void main(String[] args) {
    new Thread(() -> {
        System.out.println("default level: {}" + Thread.currentThread().getPriority());
    }).start();
}

输出: default level: {}5

设置级别

public static void main(String[] args) {
    Thread t = new Thread(() -> {
        System.out.println("default level: {}" + Thread.currentThread().getPriority());
    });
    t.start();
    t.setPriority(10);
}

输出: default level: {}10

通常来讲,高级别的优先级往往会更高几率的执行,注意这里是概率性问题,下面我们测试一下

public static void main(String[] args) {
    Thread t = new Thread(() -> {
        System.out.println("hello " +  Thread.currentThread().getPriority());
        System.out.println("default level: {}" + Thread.currentThread().getPriority());
    });
    t.setPriority(3);

    Thread t1 = new Thread(() -> {
        System.out.println("hello " +  Thread.currentThread().getPriority());
        System.out.println("default level: {}" + Thread.currentThread().getPriority());
    });
    t1.setPriority(7);

    Thread t2 = new Thread(() -> {
        System.out.println("hello " +  Thread.currentThread().getPriority());
        System.out.println("default level: {}" + Thread.currentThread().getPriority());
    });
    t2.setPriority(10);


    t.start();
    t1.start();
    t2.start();
}

第一次输出:

hello 7
default level: {}7
hello 10
default level: {}10
hello 3
default level: {}3

第二次:

hello 3
default level: {}3
hello 7
default level: {}7
hello 10
default level: {}10

第三次

hello 10
default level: {}10
hello 7
default level: {}7
hello 3
default level: {}3

...

发现,不断的尝试之后,高级别出现的概率会比较靠前一点, 所以想要借助它来完成一些特定业务的同学注意了,不建议使用,不靠谱,之前也讲到,底层还是由操作系统调度完成

Java提供一个「线程调度器」来监视和控制处于「RUNNABLE状态」的线程。线程的调度策略采用「抢占式」,优先级高的线程比优先级低的线程会有更大的几率优先执行。在优先级相同的情况下,按照“先到先得”的原则。每个Java程序都有一个默认的主线程,就是通过JVM启动的第一个线程main线程。

除了主线程之外,还有一个线程是守护线程,它的优先级比较低。如果所有的非守护线程都结束了,这个守护线程也会自动结束。可以借助它实现一些特定场景,比如手动关闭线程的场景,某些场景下不关闭,会造成资源浪费,手动关闭又很麻烦。这里我们可以通过setDaemon(true)指定

public static void main(String[] args) {
    Thread t = new Thread(() -> {
        System.out.println("hello " +  Thread.currentThread().getPriority());
        System.out.println("default level: {}" + Thread.currentThread().getPriority());
    });
    t.setDaemon(true); // 默认为false
    t.setPriority(10);

    Thread t1 = new Thread(() -> {
        System.out.println("hello " +  Thread.currentThread().getPriority());
        System.out.println("default level: {}" + Thread.currentThread().getPriority());
    });
    t1.setPriority(7);

    t.start();
    t1.start();
}

输出:

hello 7
default level: {}7
hello 10
default level: {}10

发现即使指定了高级别,执行的优先级仍然是最低的

线程组下的优先级

刚刚我们都是在main线程组下,举一反三,线程组下的优先级又是怎么样的呢❓下面,测试一下

public static void main(String[] args) {
        // 指定 name 为 g1的线程组
        ThreadGroup group = new ThreadGroup("g1");
        group.setMaxPriority(4);

        Thread t = new Thread(group, () -> {
            System.out.println("hello " +  Thread.currentThread().getPriority());
            System.out.println("default level: {}" + Thread.currentThread().getPriority());
        }, "t0");
        t.setPriority(10);
        t.start();
    }

输出:

hello 4
default level: {}4

发现,在g1线程组下指定了最大优先级后,线程t0的优先级最大级别只能是4, 所以这也是使用线程组的好处。

我们可以通过如下方式复制线程组, ThreadGroup提供了enumerate方法

public static void main(String[] args) throws InterruptedException {
        // 指定 name 为 g1的线程组
        ThreadGroup group = new ThreadGroup("g1");
        group.setMaxPriority(4);

        Thread t = new Thread(group, () -> {
            System.out.println("hello " +  Thread.currentThread().getPriority());
            System.out.println("default level: {}" + Thread.currentThread().getPriority());
        }, "t0");
        t.setPriority(10);
        t.start();

        // 复制线程组
        System.out.println(group.activeCount()); // 1
        Thread[] list = new Thread[group.activeCount()];
        group.enumerate(list);

        Thread.sleep(3000);
        System.out.println(list[0].getName()); // 输出 t0

    }

统一异常捕获

    public static void main(String[] args) {
        // 指定 name 为 g1的线程组
        ThreadGroup group = new ThreadGroup("g1") {
            // 统一异常捕获
            public void uncaughtException(Thread t, Throwable e) {
                System.out.println(t.getName() + ": " + e.getMessage()); // t0: 我出错了
            }
        };
        group.setMaxPriority(4);

        Thread t = new Thread(group, () -> {
            System.out.println("hello " +  Thread.currentThread().getPriority());
            System.out.println("default level: {}" + Thread.currentThread().getPriority());
            throw new RuntimeException("我出错了");
        }, "t0");
        t.setPriority(10);
        t.start();
    }

向下引用的树状数据结构

线程组的内部其实不单单可以放线程,其实也可以放其它线程组,我们看下源码定义

    private final ThreadGroup parent;
    String name;
    int maxPriority;
    boolean destroyed;
    boolean daemon;
    boolean vmAllowSuspension;

    int nUnstartedThreads = 0;
    int nthreads;
    Thread threads[];

    int ngroups;
    ThreadGroup groups[];

这里大家可以大胆去猜测一下,为什么要采用这种数据结构❓其实你通过源码发现,它的内部很多地方都调用了checkAccess方法,特别是在set操作,字面意思是检查是否有权限,我看下这个方法

public final void checkAccess() {
    SecurityManager security = System.getSecurityManager();
    if (security != null) {
        security.checkAccess(this);
    }
}

它调用了一个SecurityManager, 它是Java的安全管理器,它允许应用程序在执行一个可能不安全或敏感的操作前确定该操作是什么,以及是否是在允许执行该操作的安全上下文中执行它。应用程序可以允许或不允许该操作。总的来说就是保证安全性。

通过上面的了解,我们应该知道为什么要用这种树状结构了。它都是一层一层级别的控制,这么做方便去管理,提高安全性,出了问题也能很快的定位到。就像公司的人员组织架构一样,一切都是为了管理好公司。

结束语

本篇内容到这里就结束了, 大家自己一定要多去理解,不要去背,下期给大家讲讲线程的状态以及它的生命周期~

关注关注,主页更多java内容

 

javajava 线程ThreadGroup 1.概述 转载:线程组是什么?线程优先级如何设置? 2. 线程组(ThreadGroup) Java中用ThreadGroup来表示线程组,我们可以使用线程组对线程进行批量控制。 ThreadGroupThread的关系就如同他们的字面意思一样简单粗暴,每个Thread必然存在于一个ThreadGroup中,Thread不能独立于ThreadGroup存在。执行main()方法线程的名字是main,如果在new Thread时没有显式指定,那么默认将父线程(当前执行new Thread的线程线程组设置. 阅读详情

相关推荐

电路设计仿真软件:Mentor Graphics_(11).MentorGraphics软件操作与技巧

/ 定义自定义仿真命令// 加载设计文件// 运行仿真// 主函数return 1;return 0;// 自定义设计检查// 获取设计中的所有模块// 遍历所有模块// 检查模块名称是否符合规范if (!// 检查模块中的所有引脚if (!// 主函数main() {通过本节的学习,您应该已经掌握了如何在 Mentor Graphics 中进行二次开发,包括使用 Tcl、C++ Python 进行基本高级操作。

kkchenjj的博客 1569

线程线程优先级

线程线程优先级 线程组(ThreadGroup) 我们可以使用线程组对线程进行批量控制 ThreadGroupThread的关系:每个Thread必然存在于一个ThreadGroup中,Thread不能独立在ThreadGroup存在。执行main()方法线程的名字是main,如果new Thread时没有显式指定,那么默认将父线程(当前执行new Thread的线程线程组设置为自己的线程ThreadGroup一个标准向下引用的树形结构,这样设计原因防止上级线程被“下级”线程引用而无

weixin_51438023的博客 4026

火灾烟雾目标检测数据集.zip

数据集介绍:火灾烟雾目标检测数据集一、基础信息• 数据集名称: 火灾烟雾目标检测数据集• 图片数量:训练集:7844张图片验证集:510张图片测试集:382张图片总计:8736张图片• 训练集:7844张图片• 验证集:510张图片• 测试集:382张图片• 总计:8736张图片• 分类类别:Fire(火灾):表示火焰或火灾区域,适用于火灾检测任务。Smoke(烟雾):表示烟雾区域,适用于烟雾识别任务。• Fire(火灾):表示火焰或火灾区域,适用于火灾检测任务。• Smoke(烟雾):表示烟雾区域,适用于烟雾识别任务。• 标注格式: YOLO格式,包含边界框类别标签,适用于目标检测任务。• 数据格式: JPEG图片,来源于真实场景(如监控、航拍等),覆盖多样环境。二、适用场景• 火灾烟雾检测系统开发: 用于构建AI模型,自动识别火焰烟雾区域,适用于森林防火、城市安防监控等场景。• 安全监控与预警应用: 集成到CCTV或无人机系统中,实时检测火灾风险,提升应急响应效率。• 环境风险评估与管理: 支持火灾烟雾的早期预警,用于环境监测、灾害预防等领域。• 计算机视觉研究: 促进目标检测算法在火灾安全领域的创新与应用。三、数据集优势• 精准标注: 数据集基于YOLO格式标注,边界框定位准确,确保模型训练可靠性。• 场景多样性: 数据来源于航拍、监控等多种真实场景,覆盖不同光照环境条件,增强模型泛化能力。• 任务适配性强: 标注兼容主流深度学习框架(如YOLO),可直接用于目标检测模型开发。• 实用价值突出: 专注于火灾烟雾检测,为公共安全、环境保护提供高质量数据支持。

联壁峰--多线程系列之线程线程优先级(三)

小宋带大家继续深入多线程的学习,本章讲解一下关于线程组以及线程优先级的相关知识。 目录线程线程优先级线程组的常用方法及数据结构线程组的常用方法线程组的数据结构 线程组 我们先普及一下线程组的概念。 java中用ThreadGroup来表示线程组,我们可以使用线程组对线程进行批量操作。 ThreadGroupThread的关系就如同他们的字面意思,每个Thread必然存在于一个ThreadGroup中,Thread不能独立于ThreadGroup存在。执行main()方法线程的名字是main,如果在.

小宋的博客 1533

守护线程线程优先级的理解

守护线程是一种特殊类型的线程,它的目的是为其他线程提供服务,当所有的非守护线程结束时,守护线程也会随之结束,无论它是否执行完毕。守护线程是通过设置线程的daemon属性为True来创建的。守护线程会随着程序的结束而结束,即使它还没有执行完毕。守护线程不能用于执行一些需要完整执行的操作,比如文件写入等,因为它可能会在程序结束之前就被终止。守护线程通常用于执行一些后台任务,比如定时任务、垃圾回收等。

qq_39939541的博客 644

线程优先级、守护线程、礼让线程、插入线程、中断线程

一. 线程优先级一. 线程优先级在计算机当中,线程的调度有两种方式:抢占式调度模型多个线程它是在抢夺CPU的执行权,CPU在什么时候执行哪条线程是不确定的,执行多长时间也是不确定的,所以抢占式调度它体现了一个随机性优先级高的线程获取的 CPU 时间片相对多一些。非抢占式调度 / 分时调度模型所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间片轮流的执行执行的时间也是差不多的在Java当中,它采取了第一种抢占式调度模型的方式。抢占式调度,重点掌握两个字随机性。

weixin_53622554的博客 1749

ThreadGroup

本文不会对ThreadGroup如何使用进行分析,而是通过解析ThreadGroup的树形结构实现,以便更好的理解ThreadGroup设计意义

慎思谨学欲乘风 1万+

【并发编程】JAVA线程与并发编程(一)

1. 进程与线程 1.1 进程的由来 从计算机的发展历程来讲,最初的计算机只能接受一些特定的指令,用户输入什么,计算机就做出相对应的操作,其他时间计算机就处于等待之中,这时的效率非常低下;后来有了批处理操作系统,就是把一系列需要操作的指令写下来,形成一个清单,一次性交给计算机执行,但是批处理操作系统的指令运行方式仍然是串行的,内存中始终只有一个程序在运行,后面的任务需要等待上一个任务执行结束之后才能执行。 面对日益增长的性能要求,于是先辈们提出了进程的概念:进程是一个具有独立功能的程序关于某个数据集合的一次

罗伯司机的博客 303

java线程:线程基础

文章目录线程创建线程通知与等待虚假唤醒wait()、wait(long timeout)、wait(long timeout,int nanous)函数notify()、notifyAll()函数等待线程执行终止的join方法让线程睡眠的sleep方法Sleep方法与wait方法区别让出CPU执行权的yield方法sleep()与yield()区别线程中断线程死锁为什么会产生死锁??如何避免线程死锁?守护线程与用户线程线程线程优先级线程线程优先级线程组的常用方法及数据结构ThreadLocal 线程

朱小猿 404

代码理解java线程 (一) - 基础篇(1)

第一章 进程与线程的基本概念 1.1 进程产生的背景 最初的计算机只能接受一些特定的指令,用户每输入一个指令,计算机就做出一个操作。当用户在思考或者输入时,计算机就在等待。这样效率非常低下,在很多时候,计算机都处在等待状态。 批处理操作系统 后来有了批处理操作系统,把一系列需要操作的指令写下来,形成一个清单,一次性交给计算机。用户将多个需要执行的程序写在磁带上,然后交由计算机去读取并逐个执行这些程序,并将输出结果写在另一个磁带上。 批处理操作系统在一定程度上提高了计算机的效率,但是由于批处理操作系

zzqtty的博客 414

java笔试面试(三)

垃圾回收机制,冲高薪必备知识。

m0_72323808的博客 265

数据库索引 引用树形结构 B-数 B+数

MySQL 为什么使用B+数 B-树B+树最重要的一个区别就是B+树只有叶节点存放数据,其余节点用来索引,而B-树是每个索引节点都会有Data域。 这就决定了B+树更适合用来存储外部数据,也就是所谓的磁盘数据。从Mysql(Inoodb)的角度来看,B+树是用来充当索引的,一般来说索引非常大,尤其是关系性数据库这种数据量大的索引能达到亿级别,所以为了减少内存的占用,索引也会被存储在磁盘上。那...

weixin_34259559的博客 251

SQL 树状数据查询之向下包含

with a as( select ntID,ntParentID,ntName from tb_NewsType where ntID='9' union all select x.ntID,x.ntParentID,x.ntName from  tb_NewsType x,a where x.ntParentID=a.ntID) select * from a

ly1577592799的专栏 839

Java中垃圾回收(gc)问题

以下哪项陈述是正确的? A. 垃圾回收线程优先级很高,以保证不再 使用的内存将被及时回收 B. 垃圾收集允许程序开发者明确指定释放 哪一个对象 C. 垃圾回收机制保证了JAVA程序不会出现 内存溢出 D. 进入”Dead”状态的线程将被垃圾回收器回收 E. 以上都不对 答案:E 解析: A: 垃圾回收在jvm优先级相当相当低。 B:垃圾收集器(GC)程序开发者只能推荐JVM进行

xl_love的专栏 7291

android进程、线程优先级

一个面试问题:IntentService的优先级比单纯的线程高,它不容易被系统杀死,可以执行高优先级的后台任务。为什么?它的背后有那些逻辑呢? IntentService的具体内容可以参照我的另外一篇文章:IntentService的源码分析,IntentService也是Service,后续就把IntentService改为Service了,更有代表性。表面看是涉及到两个知识点的问题,一是a

JoneRen的博客 997

线程优先级

线程优先级用1-10之间的整数表示,数值越大优先级越高,默认的优先级为5。Thread thread = new Thread(new MyRunnable()); thread.setPriority(10);

小红威武 1679

JVM垃圾回收引用优先级

https://www.processon.com/view/link/59562717e4b04e84184d8faa

WALKMAN'S BLOG 1461

垃圾回收机制

以下哪项陈述是正确的(E) A.垃圾回收线程优先级很高,以保证不再使用的内存将被及时回收 B.垃圾收集允许程序开发者明确指定释放哪一个对象 C.垃圾回收机制保证了JAVA程序不会出现内存溢出 D.进入"Dead"状态的线程将被垃圾回收器回收 E.以上都不对 分析: A: 垃圾回收在jvm优先级相当相当低。 B:垃圾收集器(GC)程序开发者只能推荐JVM进行回收,但何时回

﹎厡.唻 4811

线程优先级守护线程

1、线程优先级 java中的线程优先级的范围是1~10,默认的优先级是5。高优先级线程会优先于低优先级线程执行(数字越大优先级越高)。在一个线程内新建一个线程对象,则新建线程优先级默认线程一样。示例: public class PriorityThread extends Thread { public PriorityThread(String name) { super(n...

如不來的博客 254
上一篇: 面试官: 有了解过ReentrantLock的底层实现吗?说说看
下一篇: Java多线程专题之线程类和接口入门
十一技术斩
博客等级 码龄5年 4512粉丝 · 487原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值