朝闻道,夕死可矣
红色:重点方法名 或者是 注释解析
黄色:《书名》
蓝色:专有名词
绿色:源码解析
紫色:源码变量含义
棕色:线程状态
粉色:上文内容
文章目录
一英文注释
java虚拟机允许程序中多个线程运行
每个线程都有一个优先级,优先级高的线程优先运行与低优先级线程
每个线程都可以是守护线程
在一个线程里面创建子线程时,子线程继承父线程优先级,并且当父线程是守护线程时子线程也是守护线程
当JVM虚拟机启动时,通常会有一个非守护线程来调用某个类的指定main方法
JVM虚拟机继续执行直到碰到下面 两种 情况:情况一:
- 已调用 Runtime 类的退出方法 , 并且安全管理器已允许退出操作发生.
1.1Runtime解释Runtime的退出方法1.1Runtime
这个Runtime类是干什么的?
Runtime是用来让
应用程序与应用程序运行的 环境进行交互
在Runtime类中有一个exit()方法,可以停在正在运行的虚拟机
在Runtime类只有一种初始化方式:
哪就是调用其静态的getRuntime()方法
让我们一起来试一下这个Runtime的exit()方法吧
可以看到,jvm虚拟机停在后,15行代码没有被执行情况二:
- 除了守护线程的其它线程都死亡时,或者是return或者是抛出异常时
有两种方式创建新线程,
1.将类声明成Thread的子类,这个子类覆盖Thread的run方法,
例如,计算大于规定值的素数的线程可以写成如下:
2. 声明一个实现 Runnable 接口的类,.实现类实现run方法,
例如,如下
每个线程都一个名称,如果创建线程时没有指定名称,系统会自动生成一个名称
除非另有说明,否则将空参数传递给此类中的构造函数或方法将导致抛出 NullPointerException。
二变量的初始化
为了搞清楚这个4行代码,我们先来了解一下本地方法
本地方法是指在Java类用被native修饰的没有实现的方法在《深入Java虚拟机》这个本书的1.3.1对Java方法的描述:
Java有两种方法:Java方法和本地方法.
Java方法是由Java语言编写,编译成字节码,存储在class文件中.
格式与平台无关
本地方法是由其他语言编写的,编译成和处理器相关的机器代码,
格式是各个平台专有的,保存在动态连接数据库中,
当被调用时,虚拟机装载包含这个本地方法的动态连接数据库
.
本地方法 是 联系Java程序和底层主机操作系统的连接方法registerNatives()方法就是一个用来注册本地方法的,
Q1 注册了哪些方法?
注册的方法就是该类所包含的除了registerNatives()方法以外的所有本地方法Q2 为什么需要注册?
在《The Java Native Interface Programmer’s Guide and Specification》这本书的8.3Registering Native Methods来回答这个问题
.
一个java程序要想调用一个本地方法,需要两步1,通过System.loadLibrary()将包含本地方法实现的动态文件加载进内存
2,虚拟机在加载的动态文件中定位并连接该本地方法,从而得以执行本地方法
registerNatives()方法的作用就是取代第二步,
让程序主动将本地方法链接到调用方,
当Java程序需要调用本地方法时就可以直接调用
而不需要虚拟机再去定位并链接
.
书中还总结了所用registerNatives()方法的四点好处
- 在类被加载时就主动将本地方法链接到调用方,比如方法被使用时才由虚拟机来定位链接更方便有效
- 如果本地方法在程序运行中更新了,可以通过调用registerNatives()进行更新
- Java程序需要调用一个本地应用提供的方法时,因为虚拟机只会检索本地动态库,因而虚拟机是无法定位到本地方法实现的,这个时候只能使用registerNatives()方法进行主动链接
- 通过registerNatives()方法在定义本地方法实现的时候,可以不遵守JNI命名规范,
JNI命名规范:要求本地方法名由 包名+方法名 构成,
例如,Tread类中的registerNatives()方法对应的本地方法名叫
Java_java_lang_Thread_registerNatives
Object类中的registerNatives()方法对应的本地方法名叫
Java_java_lang_Object_registerNativesQ3 具体怎么注册的?
这个问题涉及到registerNatives()方法底层C++源码实现,
点击跳转–>关于调用约定(cdecl、fastcall、、thiscall) 的一点知识(用汇编来解释)good
点击跳转–>使用JNI_OnLoad动态注册函数
回归主线Thread类
那么这个Runnable又是干什么的?
2.1Runnable
2.1.1 Runnable注释
Runnable接口的实例由线程所执行的类实现,
这个类必须定义一个名为 run() 的无参方法
.
如果 Runnable由Thread实现,处于 运行状态 仅意味着线程已启动且尚未停止
.
此外,Runnable提供了使类处于 运行状态 而不是子类化Thread的方法
通过实例化Thread实例并将自身作为目标传入,实现Runnbale的了可以在不继承Thread类的情况下运行
.
然而大多数情况下,只覆盖 run() 方法而不是覆盖其它的Thread的方法,就可以使用Runanle接口2.1.2 Runnable注解
此注解是 JDK8新特性 中的 函数式接口 的伴生品
该注解的特点:
- 只能标记在有且仅有一个抽象方法的接口上
- JDK8接口中的静态方法和默认方法,都不算是抽象方法
- 接口默认继承Java.lang.Object,所以如果接口显示声明覆盖了Object方法,那也不算抽象方法
- 改注解不是必须的,如果一个接口符合函数式接口,那么加不加本注解都没有影响,加上是为了让编译器进行检查
相反,如果不是函数式接口 而加了@FunctionInterface那么编译器会报错
函数式接口的定义是:
只包含一个抽象方法的接口,
但是容许包含 默认方法 和 静态方法
函数式接口的用途
主要用在Lambda表达式上
这样就可以使用Lambda表达式来表示该接口的一个实现
Java8中常用的函数式接口:
2.1.3 Runnable 方法
当使用实现Runable接口的对象创建线程时,
启动线程会让线程调用 run()方法
run()里边可以写一些线程采取的动作
回归主线Thread类
2.2ThreadGroup
2.2.1注释
ThreadGroup代表一组线程
一个线程组还可以包含其他线程组
线程组形成一棵树,其中除了初始线程组之外的每个线程组都有一个父线程组
一个线程可以访问它自己的线程组的信息,但不能访问它的线程组的父线程组
或任何其他线程组的信息
2.2.2构造
ThreadGroup共有4个构造
这4个构造底层就是下图这个构造
从这个构造中,我们可以得出:
一个线程组核心信息是:名称,优先级,是否守护,父线程组,子线程组
还有一个默认的构造,用来创建系统线程组
add(ThreadGroup g)添加线程组
add(Thread t)添加线程
所以通过以上方法组成了线程组的树形结构
也就是说
- 每个线程组知道自己包含了多少线程,有哪些线程
- 每个线程组知道自己包含了多少线程组,有哪些线程组
2.2.8子线程组相关方法
既然是树形结构,哪我们看看枚举节点的需求
如图所示:将6个方法看出两组方法
第二组
enumerate(ThreadGroup list[])
enumerate(ThreadGroup list[], boolean recurse)
enumerate(ThreadGroup list[], int n, boolean recurse)
和第一组原理相同,ThreadGroup结尾了,我们继续看Thread中定义的变量
回归主线Thread类,书接166行 private ThreadGroup group;
>
当调用java.util.concurrent.locks.LockSupport.park方法时需要的参数
由(私有)的java.util.concurrent.locks.LockSupport.setBlocker方法设置本参数
使用 java.util.concurrent.locks.LockSupport.getBlocker 访问
三本地方法
3.1currentThread()方法
3.2yield()方法
yield()让当前正在运行的线程回到 就绪状态,来让具有相同优先级的其它线程获得运行的机会,以 轮换执行 ,然而CPU可能会忽略yield()方法,因为进入 就绪状态 的线程很可能再次被CPU选中并运行
3.3sleep()方法
sleep(long millis)使当前正在执行的线程休眠(暂时停止执行)指定的毫秒数,进入 超时等待状态
这个取决于系统计时器和调度查询的精度和准确性.
这个线程不会失去任何监视器的所有权
四Java方法
4.1sleep(long millis,int nanos)方法
4.2SecurityManager类
在进入init()方法之前,先来了解一下SecurityManager类,
.
4.2.1SecurityManager类的作用
在运行未知的Java程序时,
该程序可能有恶意代码(删除系统文件,重启系统等),
为了防止运行恶意代码对系统产生影响,
需要对运行的代码的权限进行控制
SecurityManager类就是 Java安全管理器
.
4.2.2 启动安全管理器方式一:启动参数
启动程序时通过附加参数启动Java安全管理器
-Djava.security.manager
若要同时制定配置文件的位置需要如下示例:
-Djava.security.manager
-Djava.security.policy="E:/java.policy"
方式二:编码方式启动
在这里插入代码片
4.3init()方法及其重载方法