Java Thread基础(2)
线程管理:线程组
在系统中如果线程数量很多,而且功能分配比较明确,就可以把相同功能的线程放置在一个线程组里。
可以把线程归属到某一个线程组中,线程组中可以有线程对象,也可以有线程组,组中还可以有线程,这样的组织结构有点类似于树的形式。
线程组的作用是:可以批量管理线程或线程组对象,有效地对线程或线程组对象进行组织。
一级关联(ThreadGroup -> Thread)
- Thread 对象通过构造器初始化时传入ThreadGroup对象,实现与ThreadGroup对象的关联。
1 | public Thread(ThreadGroup group, String name){...} |
- Thread 对象通过方法
getThreadGroup()
可以获得所属线程组。
批量中断组内线程
- ThreadGroup 对象通过
ThreadGroup.interrupt()
方法批量中断组内线程。
例子
1 | public class ThreadGroup2ThreadDemo { |
- output
1 | 线程组中活动线程数量0 |
多级关联(ThreadGroup -> ThreadGroup)
- ThreadGroup 对象之间的关联关系也是通过构造器建立。
1 | public ThreadGroup(ThreadGroup parent, String name){...} |
ThreadGroup 对象通过方法
getParent()
可以获得父线程组。父级线程组的中断方法会调用子级线程组的中断方法。
1 | // 摘自 openJDK 源码 |
线程组的递归处理
list()
Prints information about this thread group to the standard output. This method is useful only for debugging.
上面是官方文档的说明,list方法用于向标准输出输出线程组的信息,这个方法仅用于debug。从源码中,可以看出list方法会递归输出多级关联的所有信息。
1 | public void list() { |
enumerate()
enumerate方法的作用是枚举线程组的内容,把内容放入对应的容器中。enumerate 既可以枚举当前线程组的线程也可以枚举当前线程组的子线程组。enumerate()
的递归与非递归控制是通过boolean值控制的。
1 | public int enumerate(ThreadGroup list[], boolean recurse) {...} |
显然从源码中可以看出,当传参为true时,会进行递归操作。
1 | private int enumerate(Thread list[], int n, boolean recurse) { |
例子
1 | public class ThreadGroup2GroupDemo { |
- output
1 | java.lang.ThreadGroup[name=parentGroup,maxpri=10] |
线程组特性
线程组自动归属特性
- 自动归属是指对于初始化时没有指定所属线程组的Thread和ThreadGroup对象,他们会被自动归属到当前线程所属的线程组中。
1 | // openJdk 1.8 源码 |
根线程组
- 根线程组就是系统线程组system,根线程组上没有父线程组。
查看OpenJdk的ThreadGroup源码,可以发现下面这段代码。这是用于C代码调用,来生成系统线程组的。
1 | /** |
未捕获异常的统一处理
1 | // openJdk 1.8 source code |
- 如果当前线程组有父线程组,调用父线程组的
uncaughtException
方法。 - 如果父线程组不存在,但是有默认异常处理器,调用异常处理器的
uncaughtException
方法。 - 如果没有指定异常处理器,输出异常日志。注意,如果异常是
ThreadDeath
,忽略该异常。
可以在子类中覆盖ThreadGroup的uncaughtException
方法来统一处理线程组异常。
线程优先级
现代操作系统一般是分时操作系统,即一台计算机采用时间片轮转的方式同时为若干用户提供服务。线程分配得到的时间片的多少决定了线程使用处理器资源的多少,也对应了线程优先级这个概念。JAVA线程中使用一个int 值priority来控制优先级,范围为1-10,其中10的优先级最高,1的优先级最低。
1 | // 最小优先级 |
线程的优先级有继承性
在Java中,线程的优先级具有继承性,比如,A线程启动B线程,则B线程的优先级与A是一样。
1 | public class ThreadPriority { |
优先级规则
- CPU尽量把执行资源让给优先级高的线程,即优先级高的线程总是大部分会先执行,但是这不代笔高优先级的线程全部先执行完再执行低优先级的线程。
- 优先级具有随机性,优先级高的不一定每次都先执行。
线程优先级不能作为程序正确性的依赖,因为操作系统可以完全不用理会JAVA线程对于优先级的设定。
分析例子
1 | public class TestPriority |
显然,根据输出我们可以发现Linux 操作系统并没有理会JAVA设置的优先级。
而在window系统上,我们可能得到这样的结果:
1 | JOB priority:1,1099494 |
这就符合了线程的优先级规则。
守护(daemon)进程
Java的线程有两种类型: 用户进程和守护进程。
什么是守护进程?
守护进程是一种特殊的线程,当进程中不存在非守护线程的时候,则守护进程自动销毁,典型的守护进程是垃圾回收进程。
1 | public class DaemonTest { |