> 文档中心 > 第三章 线程组和线程优先级

第三章 线程组和线程优先级


3.1 线程组(ThreadGroup)

Java中用ThreadGroup来表示线程组,我们可以使用线程组对线程进行批量控制。
每个Thread必然存在于一个ThreadGroup中,Thread不能独立于ThreadGroup存在。执行main()方法线程的名字是main,如果zainew Thread 时没有显式指定,那么默认父线程(当前执行new Thread的线程) 线程组设置为自己的线程组。

/* @author :ls* @date :Created in 2022/4/19 10:07* @description:*/public class T1 {    public static void main(String[] args) { Thread sub_thread = new Thread(()->{     System.out.println("sub_thread--->当前线程组名字- >"+Thread.currentThread().getThreadGroup().getName());     System.out.println("sub_thread--->当前线名字-->"+Thread.currentThread().getName()); }); sub_thread.start(); System.out.println("main方法----->"+Thread.currentThread().getName());    }}

输出结果:

main方法----->mainsub_thread--->当前线程组名字-->mainsub_thread--->当前线名字-->Thread-0

ThreadGroup管理着它下面的Thread,ThreadGroup是一个标准的向下引用的树状结构,这样设计的原因是防止“上级”线程被“下级”线程引用而无法有效的被GC回收

3.2 线程的优先级

java中线程的优先级默认值是5,可指定范围为:1~10。在这里 java知识给操作系统一个优先级的参考值,线程最终在操作系统的优先级是多少还是由操作系统决定,也就是cpu对线程的调度,不完全是按优先级来执行的。

使用方法 setPriority() 来设定线程的优先级。

public class Demo {    public static void main(String[] args) { Thread a = new Thread(); System.out.println("我是默认线程优先级:"+a.getPriority()); Thread b = new Thread(); b.setPriority(10); System.out.println("我是设置过的线程优先级:"+b.getPriority());    }}

输出结果:

我是默认线程优先级:5我是设置过的线程优先级:10

当然这里设置线程的优先级,在实际的业务实现中是不建议采用的!! 首先来说 java线程中的优先级不是特可靠,其次硬件的配置(如 cpu) 不同对于线程执行来说也是有影响的。

public class Demo {    public static class T1 extends Thread { @Override public void run() {     super.run();     System.out.println(String.format("当前执⾏的线程是:%s,优先级:%d",      Thread.currentThread().getName(),      Thread.currentThread().getPriority())); }    }    public static void main(String[] args) { IntStream.range(1, 10).forEach(i -> {     Thread thread = new Thread(new T1());     thread.setPriority(i);     thread.start(); });    }}

某次的输出:

当前执⾏的线程是:Thread-17,优先级:9 当前执⾏的线程是:Thread-1,优先级:1 当前执⾏的线程是:Thread-13,优先级:7 当前执⾏的线程是:Thread-11,优先级:6 当前执⾏的线程是:Thread-15,优先级:8 当前执⾏的线程是:Thread-7,优先级:4 当前执⾏的线程是:Thread-9,优先级:5 当前执⾏的线程是:Thread-3,优先级:2 当前执⾏的线程是:Thread-5,优先级:3

这个结果 多次执行,结果是不同的。

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

此外,还有一种线程称作:“守护线程 (Daemon)” 守护线程默认优先级比较低

  • 如果某线程是守护线程,那如果所有的非守护线程结束,这个守护线程也会 自动结束。
  • 应用场景是:当所有非守护线程结束时,结束其余的子线程(守护线程)自动关闭,就免去了还要继续关闭⼦线程的麻烦。
  • 应用场景是:当所有非守护线程结束时,结束其余的子线程(守护线程)自动关闭,就免去了还要继续关闭⼦线程的麻烦。

线程与线程组的优先级不同时,将会怎样呢??

public static void main(String[] args) {    ThreadGroup threadGroup = new ThreadGroup("t1");    threadGroup.setMaxPriority(6);    Thread thread = new Thread(threadGroup,"thread");    thread.setPriority(9);    System.out.println("我是线程组的优先级"+threadGroup.getMaxPriority());    System.out.println("我是线程的优先级"+thread.getPriority());}

输出:

我是线程组的优先级6我是线程的优先级6

从结果来看,如果线程与所在线程组的优先级发生冲突时,该线程的优先级会失效,以线程组的最大优先级替代。

3.3 线程组的常用方法及数据结构

3.3.1 线程组的常用方法

获取当前线程组的名字:

Thread.currentThread().getThreadGroup().getName()

复制线程组:

Thread[] threads = new Thread[threadGroup.activeCount()];TheadGroup threadGroup = new ThreadGroup();threadGroup.enumerate(threads);

线程组 统一异常处理

/* @author :ls* @date :Created in 2022/4/19 10:54* @description:*/public class T2 {    public static void main(String[] args) { ThreadGroup threadGroup = new ThreadGroup("group1"){     /      * 继承ThreadGroup并重新定义一下方法      * 在线程成员抛出unchecked exception      * 会执行此方法      * */     @Override     public void uncaughtException(Thread t, Throwable e){  System.out.println(t.getName()+": "+e.getMessage());     } }; Thread thread = new Thread(threadGroup,new Runnable() {     @Override     public void run() {  //抛出 unchecked 异常  throw new RuntimeException("测试异常!!");     } },"mythread"); thread.start();    }}

执行结果:

mythread: 测试异常!!

3.3.1 线程组的数据结构

线程组不仅可以包含线程,也可以包含线程。

ThreadGroup 中的成员变量:

public class ThreadGroup implements Thread.UncaughtExceptionHandler {    private final ThreadGroup parent; // ⽗亲ThreadGroup    String name; // ThreadGroupr 的名称    int maxPriority; // 线程最⼤优先级    boolean destroyed; // 是否被销毁    boolean daemon; // 是否守护线程    boolean vmAllowSuspension; // 是否可以中断    int nUnstartedThreads = 0; // 还未启动的线程    int nthreads; // ThreadGroup中线程数⽬    Thread threads[]; // ThreadGroup中的线程    int ngroups; // 线程组数⽬    ThreadGroup groups[]; // 线程组数组}

构造函数:

// 私有构造函数private ThreadGroup() {    this.name = "system";    this.maxPriority = Thread.MAX_PRIORITY;    this.parent = null;}// 默认是以当前ThreadGroup传⼊作为parent ThreadGroup,新线程组的⽗线程组是⽬前正在运⾏线public ThreadGroup(String name) {    this(Thread.currentThread().getThreadGroup(), name);}// 构造函数public ThreadGroup(ThreadGroup parent, String name) {    this(checkParentAccess(parent), parent, name);}// 私有构造函数,主要的构造函数private ThreadGroup(Void unused, ThreadGroup parent, String name) {    this.name = name;    this.maxPriority = parent.maxPriority;    this.daemon = parent.daemon;    this.vmAllowSuspension = parent.vmAllowSuspension;    this.parent = parent;    parent.add(this);}

第三个构造函数里调用了 checkParentAccess 方法,这里看看这个方法的源码:

// 检查parent ThreadGroupprivate static Void checkParentAccess(ThreadGroup parent) {    parent.checkAccess();    return null;}// 判断当前运⾏的线程是否具有修改线程组的权限public final void checkAccess() {    SecurityManager security = System.getSecurityManager();    if (security != null) { security.checkAccess(this);    }}
  • 这里涉及到 SecurityManager 这个类,它是Java的安全管理器,它允许应用 程序在执行一个可能不安全或敏感的操作前确定该操作是什么,以及是否是 在允许执行该操作的安全上下文中执行它。应用程序可以允许或不允许该操 作。
  • 比如引入了第三方类库,但是并不能保证它的安全性。
  • 其实Thread类也有一个checkAccess()方法,不过是用来当前运行的线程是 否有权限修改被调用的这个线程实例。(Determines if the currently running thread has permission to modify this thread.)

总结来说,线程组是一个树状的结构,每个线程组下面可以有多个线程或者线程 组。线程组可以起到统一控制线程的优先级和检查线程的权限的作用。