1.Thread特性分析
- 守护线程Daemon
- 定性:支持性线程,主要用于程序中后台调度以及支持性工作。
- 当JVM中不存在Daemon线程时,JVM将会退出。
- 将一个线程设定为Daemon的方法:
- 调用Thread.setDaemon(true)。
- Daemon属性的设定只能在启动线程前设置,启动线程后不能设置。
- JVM退出时Daemon线程中的finally块中的代码不一定会执行。因此不能依靠finally块中的内容来确保执行关闭或清理资源的逻辑。
- 当JVM启动时,通常会有唯一的一个非守护线程(这一线程用于调用指定类的main()方法).
- 2种方式创建一个可执行线程
- 定义一个继承Thread类的子类.子类可覆写父类的run()方法.
- 使类实现Runnable接口
- 线程名字
- 每一个线程都有一个用于目的标识的名字
- 多个线程可以有相同的名字
- 线程名类型为volatile类型,可更改且线程可见
- 线程ID
- 一个long类型的正数,在线程被创建时就有
- 在其生命周期内都不会更改且独一无二
- 当线程终止时,则此线程的ID会被重复使用
- 线程优先级
- 线程状态6种
- NEW:线程还未开始,只是进行了一些线程创建的初始化操作,但未调用start()方法.
- RUNNABLE:线程在JVM里面处于运行状态(这里就绪和运行同属于运行).
- BLOCKED:线程正在等待一个监视器锁,处于阻塞状态.
- WAITING:一个线程在等待另一个线程的特定操作(通知or中断),这种等待是无限期的.
- TIMED_WAITING:一个线程在等待另一个线程的特定操作,这种等待是有时间限制的.一旦超时则线程自行返回.
- TERMINATED:线程已退出.表示线程已经执行完毕.
- 浅拷贝
2. 类、方法、字段分析
- 实现接口和继承类
只实现了一个接口Runnable
- threadLocals变量
- 类型为:ThreadLocal.ThreadLocalMap
- 功能:此线程的本地变量值.此map由ThreadLocal类进行维护,因为这个类在ThreadLocal中是包级私有的.
- ThreadLocalMap:一个用于维护线程本地变量的hashmap,此hashmap的key引用类型为弱引用,这是为了支持大且长期存活的使用方法.
- inheritableThreadLocals变量
- 类型:ThreadLocal.ThreadLocalMap
- 功能:和此线程相关的由继承得到的本地变量值
- public static native void yield()方法
- 功能:
提示线程调度器当前线程愿意放弃当前CPU的使用。当然调度器可以忽略这个提示
- 设计目的:
让出CPU是一种启发式的尝试,以改善线程之间的相对进展,否则将过度利用CPU。
- 使用场景:
此方法很少有适用的场景.它可以用用于debug或者test,通过跟踪条件可以重现bug
- public final synchronized void setName(String name)方法
- 3个join方法
- 功能:等待直到线程终止
- public final synchronized void join(long millis)
- 最多等待参数millis(ms)时长当前线程就会死亡.参数为0时则要持续等待
- 此方法为同步方法
- public final synchronized void join(long millis, int nanos)
- 等待时间单位为纳秒,其它解释都和上面方法一样
- 此方法为同步方法
- public final void join() throws InterruptedException
- toString()格式
线程名+优先级+所属组别
- @CallerSensitive注解
- 功能:
这个注解是为了堵住漏洞用的
- 原理:
曾经有黑客通过构造双重反射来提升权限,原理是当时反射只检查固定深度的调用者的类,看它有没有特权.使用CallerSensitive后,getCallerClass不再用固定深度去寻找actual caller(“我”),而是把所有跟反射相关的接口方法都标注上CallerSensitive,搜索时凡看到该注解都直接跳过,这样就有效解决了这类的黑客问题.
3.源码分析
package sourcecode.analysis;
/**
* @Author: cxh
* @CreateTime: 18/5/11 19:11
* @ProjectName: JavaBaseTest
*/
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.security.AccessController;
import java.security.AccessControlContext;
import java.security.PrivilegedAction;
import java.util.Map;
import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.locks.LockSupport;
import sun.nio.ch.Interruptible;
import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;
import sun.security.util.SecurityConstants;
/**
* 线程就是程序中一个线程的执行.JVM允许一个应用中多个线程并发执行.
*
* 每个线程都有优先级.高优先级线程优先于低优先级线程执行.
* 每个线程都可以(不可以)被标记为守护线程.
* 当线程中的run()方法代码里面又创建了一个新的线程对象时,新创建的线程优先级和父线程优先级一样.
* 当且仅当父线程为守护线程时,新创建的线程才会是守护线程.
*
* 当JVM启动时,通常会有唯一的一个非守护线程(这一线程用于调用指定类的main()方法)
* JVM会持续执行线程直到下面情况某一个发生为止:
* 1.类运行时exit()方法被调用 且 安全机制允许此exit()方法的调用.
* 2.所有非守护类型的线程均已经终止,or run()方法调用返回 or 在run()方法外部抛出了一些可传播性的异常.
*
*
* 有2种方式可以创建一个可执行线程.
* 1.定义一个继承Thread类的子类.子类可覆写父类的run()方法.子类实例分配内存后可运行(非立即,取决于CPU调用)
* 比如:计算大于指定值的素数的线程可以写成如下
* class PrimeThread extends Thread {
* long minPrime;
* PrimeThread(long minPrime) {
* this.minPrime = minPrime;
* }
*
* public void run() {
* // compute primes larger than minPrime
* . . .
* }
* }
* 下面的代码将创建一个线程并启动它.
* PrimeThread p = new PrimeThread(143);
* p.start();
*
* 2.另一个实现线程的方式就是使类实现Runnable接口.
* 此类自己会实现run()方法.然后此线程会被分配内存,当线程被创建时,会传入一个参数,然后开始执行.
* 此种方式的样例代码如下:
*
* class PrimeRun implements Runnable {
* long minPrime;
* PrimeRun(long minPrime) {
* this.minPrime = minPrime;
* }
*
* public void run() {
* // compute primes larger than minPrime
* . . .
* }
* }
* 下面的代码能够创建一个线程并开始执行:
* PrimeRun p = new PrimeRun(143);
* new Thread(p).start();
*
* 每一个线程都有一个用于目的标识的名字.多个线程可以有相同的名字.
* 线程被创建时如果名字没有被指定,则系统为其自动生成一个新的名字.
*
* 除非特别说明,否则在创建线程时传入一个null参数到构造器或者方法会抛出空指针异常NullPointerException
*
* @author unascribed
* @see Runnable
* @see Runtime#exit(int)
* @see #run()
* @see #stop()
* @since JDK1.0
*/
public class Thread implements Runnable {
//确保本地注册(类构造器方法<clinit>方法用于类初始化)是创建一个线程首要做的事情.
private static native void registerNatives();//注册的都是一些本地方法
static {
registerNatives();
}
private volatile String name;//线程名:可更改且线程可见
private int priority;//线程优先级用一个int数字表示
private Thread threadQ;//
private long eetop;
//是否单步执行此线程
private boolean single_step;
//此线程是否为守护线程
private boolean daemon = false;
//JVM状态
private boolean stillborn = false;
//run方法执行的目标代码
private Runnable target;
//此线程所属的组别
private ThreadGroup group;
//此类型的类加载器
private ClassLoader contextClassLoader;
//此线程继承的访问控制上下文
private AccessControlContext inheritedAccessControlContext;
//用于自动编号的匿名线程
private static int threadInitNumber;
private static synchronized int nextThreadNum() {
return threadInitNumber++;
}
//此线程的本地变量值.此map由ThreadLocal类进行维护,因为这个类在ThreadLocal中是包级私有的.
//ThreadLocalMap是一个用于维护线程本地变量的hashmap,此hashmap的key引用类型为弱引用,这是为了支持大且长期存活的使用方法.
ThreadLocal.ThreadLocalMap threadLocals = null;
//和此线程相关的由继承得到的本地变量值.
//此hashmap由InheritableThreadLocal类进行维护.
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
/*
* 此线程请求栈的深度,如果线程创建者未指定栈深度则其值为0.
* 此数字如何被使用完全取决于虚拟机自己;也有一些虚拟机会忽略此变量值.
*/
private long stackSize;
//此变量表示:在本地线程终止后,JVM私有的一个状态值
private long nativeParkEventPointer;
//线程id
private long tid;
//用于生成线程ID
private static long threadSeqNumber;
//为工具提供的线程状态值,初始化值表示当前线程还未运行
private volatile int threadStatus = 0;
//私有同步方法,获取下一个线程id
private static synchronized long nextThreadID() {
return ++threadSeqNumber;
}
/**
* 此变量为用于调用java.util.concurrent.locks.LockSupport.park方法的参数.
* 其值由方法(private) java.util.concurrent.locks.LockSupport.setBlocker进行设定.
* 其值访问由方法java.util.concurrent.locks.LockSupport.getBlocker进行获取.