Java Thread多线程源码剖析

Thread多线程源码剖析

源码剖析

package java.lang;

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 {

  //确保本地注册(类构造器方法方法用于类初始化)是创建一个线程首要做的事情.

  private static native void registerNatives();//注册的都是一些本地方法
  static {

      registerNatives();
  }
  
  private volatile String name;       //线程名:可更改且线程可见
    private int            priority;    //线程优先级,用int表示,有10级,初始为5
    private Thread         threadQ;     //未知
    private long           eetop;       //JVM中的JavaThread指针
    
    //是否单步执行此线程
  private boolean single_step;
  //此线程是否为守护线程
  private boolean     daemon = false;
  //虚拟机(JVM)状态
  private boolean     stillborn = false;
  //用来引用构造函数中传递的Runnable参数,run()方法执行的目标代码
  private Runnable target;
  //线程所属的组
  private ThreadGroup group;
  //线程用的上下文类加载器,该上下文类加载器可供线程加载类和资源
  private ClassLoader contextClassLoader;
  //此线程继承的访问(请求)控制上下文
  private AccessControlContext inheritedAccessControlContext;
  //计数变量,用在nextThreadNum方法中为匿名线程生成名称
  private static int threadInitNumber;
  //静态加锁的自增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进行获取.
  */
    volatile Object parkBlocker;
    /*
  * 在可中断I/O操作中,本线程中的此对象会被阻塞.
  * 如果此线程的中断状态位被设置,则应该调用此阻塞对象的中断(interrupt)方法.
  */
    private volatile Interruptible blocker;
    //设置上述blocker变量时用的锁
    private final Object blockerLock = new Object();
    
    //设定block变量的值;通过java.nio代码中的 sun.misc.SharedSecrets进行调用.
    void blockedOn(Interruptible b) {
        synchronized (blockerLock) {
            blocker = b;
        }
    }
    
    //一个线程可以拥有的最低优先级
  public final static int MIN_PRIORITY = 1;
  //线程的默认优先级
  public final static int NORM_PRIORITY = 5;
  //一个线程可以拥有的最高优先级.
  public final static int MAX_PRIORITY = 10;
    
    //返回当前正在执行线程对象的引用,需注意这是一个本地方法
    public static native Thread currentThread();
    
    /**
  * 提示线程调度器当前线程愿意放弃当前CPU的使用。当然调度器可以忽略这个提示。
  *
  * 让出CPU是一种启发式的尝试,以改善线程之间的相对进展,否则将过度利用CPU。
  * 它的使用应该与详细的分析和基准测试相结合以确保它实际上具有预期的效果。
  *
  * 此方法很少有适用的场景.它可以用于debug或者test,通过跟踪条件可以重现bug.
  * 当设计并发控制结构(如java.util.concurrent.locks包中的并发结构)时,它可能比较有用.
  */
    public static native void yield();
    
    /**
  * 此方法会引起当前执行线程sleep(临时停止执行)指定毫秒数.
  * 此方法的调用不会引起当前线程放弃任何监听器(monitor)的所有权(ownership).
  * 让出资源但是并不会释放对象锁。
  */
    public static native void sleep(long millis) throws InterruptedException;
    //millis为毫秒,nanos为纳秒,1000纳秒=1毫秒,其他跟sleep方法一样
    public static void sleep(long millis, int nanos)
    throws InterruptedException {
        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }
        if (nanos < 0 || nanos > 999999) {
            throw new IllegalArgumentException(
                                "nanosecond timeout value out of range");
        }
        if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
            millis++;
        }
        sleep(millis);
    }
    
    //初始化一个新线程的方法
    //g所属的线程组、target待执行的目标代码、name新线程的名字、stackSize用于新线程分配所需堆栈大小
    private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize) {
        init(g, target, name, stackSize, null, true);
    }
    //重载初始化方法
    //前四个参数同上
    //AccessControlContext 用于继承的访问控制上下文
    //inheritThreadLocals 如果值为true,从构造线程获取可继承的线程局部变量的初始值
    private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize, AccessControlContext acc,
                      boolean inheritThreadLocals) {
        //如果name为空,则抛空异常。
        if (name == null) {
            throw new NullPointerException("name cannot be null");
        }
        //name不为空,则将值赋给线程私有name变量
        this.name = name;
        //将调用该初始化方法的线程,设为待创建线程的父线程
        Thread parent = currentThread();
        //获取系统的安全管理工具
        SecurityManager security = System.getSecurityManager();
        //如果线程组为空
        if (g == null) {
            //首先检测其是否为一个小应用
            
            //如果有安全管理,查询安全管理需要做的工作
            if (security != null) {
                g = security.getThreadGroup();
            }
            
            //如果安全管理在线程所属父线程组的问题上没有什么强制的要求
            //线程组将使用父线程的线程组
            if (g == null) {
                g = parent.getThreadGroup();
            }
        }

        //无论所属线程组是否显示传入,都要进行检查访问.
        //检查是否允许调用线程修改线程组参数
        g.checkAccess();

        //检查是否有访问权限
        if (security != null) {
            //该函数的定义在下面,证明创建当前子类实例能够忽略安全限制
            if (isCCLOverridden(getClass())) {
                security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
            }
        }
        
        //线程组中的计数方法,
        //无论线程启动与否都需计数,以免破坏其中包含未启动线程的守护进程线程组。
        g.addUnstarted();
        //线程私有变量赋值
        this.group = g;
        this.daemon = parent.isDaemon(); //如果父线程为守护线程,则此线程也被 设置为守护线程.
        this.priority = parent.getPriority(); //当前线程继承父线程的优先级
        //如果安全管理为空,或者父线程能够忽略安全限制调用父线程的getContextClassLoader,通过反射方式获取上下文类加载器
        //否则直接获取父线程的类加载器
        if (security == null || isCCLOverridden(parent.getClass()))
            //如果安全管理器存在,且父线程的类加载器不为null,且它们不相同,且也不是父子关系,则此方法的调用会导致安全管理的方法 checkPermission的调用,用于确定对上下文类加载器的检索是否被允许.
            this.contextClassLoader = parent.getContextClassLoader();
        else
            this.contextClassLoader = parent.contextClassLoader;
            //如果父线程的访问控制上下文不为空,则将访问控制上下文直接赋值给此线程的访问控制上下文,否则通过访问控制器获取上下文
        this.inheritedAccessControlContext =
                acc != null ? acc : AccessController.getContext();
        //将目标代码Runnable对象赋给线程私有target变量 
        this.target = target;
        //设置优先级
        setPriority(priority);
        //如果继承父线程的ThreadLocal,那么将父线程的inheritableThreadLocals拷贝给该线程的inheritableThreadLocals变量;
        if (inheritThreadLocals && parent.inheritableThreadLocals != null)
            this.inheritableThreadLocals =
                ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
        /* Stash the specified stack size in case the VM cares */
        //指定存储的堆栈深度,以防虚拟机关注
        this.stackSize = stackSize;

        //为新线程设置线程ID
        tid = nextThreadID();
    }
    
    //线程不支持浅拷贝,取而代之的是构造一个新的线程
    @Override
    protected Object clone() throws CloneNotSupportedException {
        throw new CloneNotSupportedException();
    }
    
    //分配一个新的线程对象.此构造器和Thread(ThreadGroup,Runnable,String) 构造器的效果一样.
    //初始化函数参数:(null,null,gname),其中@code gname是新生成的名称。
    //生成名字的格式为“Thread-”+n,其中n是整数。
    public Thread() {
        init(null, null, "Thread-" + nextThreadNum(), 0);
    }
    
    //作用与上一个构造器基本相同,唯一的不同时多了一个target对象。
    //此线程启动时调用对象的run方法的。如果该参数为空,则此类的 run方法不起任何作用。
    public Thread(Runnable target) {
        init(null, target, "Thread-" + nextThreadNum(), 0);
    }
    
    //此构造器生成的线程继承控制访问上下文.
  //此构造器为非公有方法.
    Thread(Runnable target, AccessControlContext acc) {
        init(null, target, "Thread-" + nextThreadNum(), 0, acc, false);
    }
    
    //功能与第一二个公有构造器类似
    //group参数,是一个线程组,如果为空,且当前有一个安全管理器,则该组由SecurityManager类的getThreadGroup方法确定,即SecurityManager.getThreadGroup()。
    //如果没有安全管理器或security manager.getthreadgroup()方法返回空值,则该组被设置为当前线程的线程组。
    //如果当前线程无法在指定的线程组中创建线程则抛出安全异常(SecurityException)
    public Thread(ThreadGroup group, Runnable target) {
        init(group, target, "Thread-" + nextThreadNum(), 0);
    }
    
    //功能同上
    //只传入线程名
    public Thread(String name) {
        init(null, null, name, 0);
    }
    
    //功能同上
    //只传入线程组和线程名
    public Thread(ThreadGroup group, String name) {
        init(group, null, name, 0);
    }
    
    //功能同上
    //只传入目标代码和线程名
    public Thread(Runnable target, String name) {
        init(null, target, name, 0);
    }
    
    public Thread(ThreadGroup group, Runnable target, String name) {
        init(group, target, name, 0);
    }
    
    /**
  * @param stackSize 此值具有平台依赖性,有的虚拟机中此值可能很大以尽量避免栈溢出;有的虚拟机中则很小;
  * 还有的虚拟机直接忽略此值的设置.
  * @since 1.4
  */
  public Thread(ThreadGroup group, Runnable target, String name,
                  long stackSize) {
        init(group, target, name, stackSize);
    }
    
    /**
  * 此方法的调用会引起当前线程的执行;JVM会调用此线程的run()方法.
  * 结果就是两个线程可以并发执行:当前线程(从调用的start方法返回)和另一个线程(它在执行run方法).
  * 一个线程不可以同时被多次启动。
  * 尤其注意:一个线程执行完成后可能并不会再被重新执行.
  */
    public synchronized void start() {
        /**
         * This method is not invoked for the main method thread or "system"
         * group threads created/set up by the VM. Any new functionality added
         * to this method in the future may have to also be added to the VM.
         *
         * A zero status value corresponds to state "NEW".
         */
         
         /**
          * 这个方法(start)不会被main方法线程或由虚拟机所创建/设置的“系统”组线程调用。
          * 任何向此方法添加的新功能方法在未来都会被添加到虚拟机中.
          * 0状态值代表了NEW的状态
          * 若当前线程状态不为新增状态
          * 抛出线程状态不合法异常。
          */
        if (threadStatus != 0)
            throw new IllegalThreadStateException();

        /* Notify the group that this thread is about to be started
         * so that it can be added to the group's list of threads
         * and the group's unstarted count can be decremented. */
        //通知线程组该线程即将启动,以便将其添加到线程组的线程列表中,并且可以减少组的未开始线程计数器。
        group.add(this);
        //先初始化启动状态变量为失败。
        boolean started = false;
        try {
            //调用线程启动本地方法
            start0();
            //调用成功后改变启动状态变量
            started = true;
        } finally {
            //无论本地方法启动成功与否都执行下面代码
            try {
                if (!started) {
                    //如果启动失败,将调用group的线程启动失败方法将该线程置为启动失败
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
                /* do nothing. If start0 threw a Throwable then
                  it will be passed up the call stack */
                //什么都不必做,如果Start0()抛出了一个throwable那么,这个throwable会被传递到调用堆栈中。
            }
        }
    }
    
    //声明本地方法Start0()
    private native void start0();
    
    //如果这个线程构造时传入了一个单独的Runnable run对象,那么这个Runnable对象的run())方法会被调用
    //否则什么也不做
    //Thread的子类应该重写该方法
    @Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }
    
    //该方法由系统调用,以便在线程实际退出之前为其提供清理的机会。
    private void exit() {
        //如果线程组不为空
        if (group != null) {
            //那么将该线程传入线程组的线程终止方法,销毁该线程。
            group.threadTerminated(this);
            //线程销毁后将线程组置为空。
            group = null;
        }
        /* Aggressively null out all reference fields: see bug 4006245 */
        //积极地清空所有引用字段:参见bug 4006245
        target = null;
        /* Speed the release of some of these resources */
        //加快释放这些资源的速度
        threadLocals = null;
        inheritableThreadLocals = null;
        inheritedAccessControlContext = null;
        blocker = null;
        uncaughtExceptionHandler = null;
    }
    
    /**
     * 强制线程停止执行。
     * 如果安装了安全管理器,则使用this参数调用它的checkaccess方法
     * 这可能导致(在当前线程中)引发SecurityException
     * 如果此线程与当前线程不同(即,当前线程正在尝试停止其自身以外的线程),则安
     * 全管理器的checkpermission方法(带有runtimePermission(“stop
     * thread”)参数)将被调用。
     * 同样,这可能会导致抛出SecurityException(在当前线程中)
     * 这个线程被表示为该线程无论是操作异常还是抛出了新创建的ThreadDeath对象作为
     * 一个异常都会被强制停止。
     * 允许停止尚未启动的线程。
     * 如果线程最终还是启动了,那么它将立即终止。
     * 应用程序通常不应尝试捕获threaddeath异常,除非它必须执行一些特殊的清理操作
     * (请注意,threaddeah的抛出会导致try语句的finally子句在线程正式死亡之前被
     * 执行)。
     * 最顶级的错误处理器会对其它未被捕获类型的异常进行处理,但是如果未处理异常是线
     * 程死亡的实例,则不会打印消息或通知应用程序。
     *
     * @exception  SecurityException
     *             如果当前线程无法修改此线程。
     * @deprecated 这种方法本质上是不安全的。用thread.stop停止线程会导致它解锁所有
     *             已锁定的监视器(这是未限制的threaddeath异常向堆栈上传播的自然结
     *             果)。以前受这些监视器保护的任何对象都可能处于不一致状态,则损
     *             坏的对象对其他线程都可见,这可能导致它们的任意行为。
     *             stop方法的许多用法都应该被替换为只修改某个变量以指示目标线程应
     *             停止运行的代码。目标线程应定期检查该变量,如果该变量指示它将停
     *             止运行,则应按顺序从其run方法返回。如果目标线程等待很长时间(例
     *             如,在条件变量上),则应使用interrupt方法中断等待。
     *             更多的信息,参见:<a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">为什么Thread.stop, Thread.suspend and Thread.resume 用已弃用注解。
     */
    @Deprecated
    public final void stop() {
        //获得系统的安全管理器
        SecurityManager security = System.getSecurityManager();
        //如果安全管理器为空
        if (security != null) {
            //检查是否允许调用线程修改线程组参数
            checkAccess();
            //如果所请求的访问,通过给定的权限,指定的安全策略不允许根据当前有效的方法将抛出一个SecurityException。   
            if (this != Thread.currentThread()) {
                security.checkPermission(SecurityConstants.STOP_THREAD_PERMISSION);
            }
        }
        // A zero status value corresponds to "NEW", it can't change to
        // not-NEW because we hold the lock.
        // 一个零状态状态值对应于"NEW",它不能更改为"not-NEW",因我我们持有锁
        if (threadStatus != 0) {
            //如果线程被挂起,则唤醒线程;否则不执行任何操作
            resume(); // Wake up thread if it was suspended; no-op otherwise
        }

        // The VM can handle all thread states
        // 虚拟机可以处理所有线程状态
        stop0(new ThreadDeath());
    }
    
    /**
     * 抛出UnsupportedOperationException异常
     * 此方法最初设计用于强制线程停止并作为异常抛出给定的@code throwable。
     * 它本质上是不安全的(有关详细信息,请参见@link stop()),而且还生成了
     * 目标线程不准备处理的异常。
     */
    @Deprecated
    public final synchronized void stop(Throwable obj) {
        throw new UnsupportedOperationException();
    }
    
    /**
  * 此方法功能:中断当前线程.
  *
  * 除非当前线程在中断自己(这么做是允许的),此线程的checkAccess()方法被调用且可能会抛出异常SecurityException
  *
  * 1.如果当前线程由于wait类型方法、join类型方法或者sleep类型的方法的调用被阻塞,则它的中断状态将被清除且会收到一个
  * 中断异常InterruptedException
  *
  * 2.如果此线程由于java.nio.channels.InterruptibleChannel类中的InterruptibleChannel的I/O操作而被阻塞,
  * 则此方法会导致通道被关闭,且线程的中断状态会被重置,同时线程会收到一个ClosedByInterruptException.异常
  *
  * 3.如果此线程由于java.nio.channels.Selector而阻塞,则线程的中断状态会被重置,且它将立即从阻塞的selection操作返回,
  * 且返回值通常是一个非零值,这就和java.nio.channels.Selector#wakeup的wakeup()方法被调用一样.
  *
  * 4.如果前面的条件都不成立,那么该线程的中断状态将被重置.。
  *
  * 中断一个处于非活着状态的线程并不需要产生任何其它影响.
  *
  * @revised 6.0
  * @spec JSR-51
  */
    public void interrupt() {
        //如果当前线程不等于当前正在执行的线程
        //那么检查是否允许调用线程修改线程组参数
        if (this != Thread.currentThread())
            checkAccess();
        //对阻塞锁使用同步机制
        synchronized (blockerLock) {
            Interruptible b = blocker;
            if (b != null) {
                interrupt0();           //只是为了设定中断标识位
                b.interrupt(this); //中断当前线程
                return; 
            }
        }
        interrupt0(); //只是为了设置中断标识位
    }
    
    /**
  * 测试当前线程是否被中断.
  * 线程的中断状态会被此方法清除.
  * 换句话说,如果此方法两次调用都能成功,则第二次调用的返回结果为false(除非在第一次调用完后和第二次调用前,当前线程被再次中断)
  *
  * 因为一个线程在中断时处于非活动状态,导致该方法返回false从而导致线程中断被忽略。
  *
  * @see #isInterrupted()
  * @revised 6.0
  */
    public static boolean interrupted() {
        return currentThread().isInterrupted(true);
    }
    
    /**
  * 测当前线程是否被中断.
  * 此方法的调用不会影响当前线程的中断状态.
  *
  * 因为在中断方法被调用时线程并未处于alive状态而忽略线程中断的情况会由于此方法的调用而受到影响.
  *
  * @see #interrupted()
  * @revised 6.0
  */
    public boolean isInterrupted() {
        return isInterrupted(false);
    }
    
    /**
  * 测试一些线程是否被中断.
  * 中断状态会被重置or并不依赖于之前的中断清除的值.
  */
    private native boolean isInterrupted(boolean ClearInterrupted);
    
    /**
  * Throws {@link NoSuchMethodError}.
  * 此方法在最开始被设计的目的是:不带任何清除操作的销毁一个线程.
  * 此方法被调用后线程持有的监听器依旧处于锁状态.
  * 然而,此方法从未被实现过.如果被实现,则由于悬挂的问题会带来死锁.
  * 当目标线程被销毁时,如果它持有了一个用于保护临界资源的锁,那么会导致此临界资源再也无法被其它线程使用.
  * 如果其它线程尝试对此资源进行加锁,就会导致死锁.这种死锁通常表现为"冻结"状态.
  * 所以该方法目前也被弃用
  * @throws NoSuchMethodError always
  */
    @Deprecated
    public void destroy() {
        throw new NoSuchMethodError();
    }

    //测试当前线程是否处于存活状态.如果一个线程在被启动后和死亡状态前都是存活状态.
    public final native boolean isAlive();
    
    /**
     * 将一个线程挂起
     * 首先,调用此线程的checkaccess方法时不带参数。这可能导致抛出SecurityException(在当前线程中)。
     * 如果线程处于活动状态,则它将被挂起,并且在恢复之前不会进一步进行处理。
     * @exception  SecurityException 如果当前线程无法修改此线程。
     * @see #checkAccess
     * @deprecated 此方法已被弃用,因为它本身容易死锁。如果目标线程在挂起时在保护
     * 关键系统资源的监视器上持有锁,则在恢复目标线程之前,任何线程都无法访问此资
     * 源。如果要恢复目标线程的线程在调用resume之前尝试锁定此监视器,则会导致死
     * 锁。这种死锁通常表现为“冻结”的进程。
     */
    @Deprecated
    public final void suspend() {
        //检查是否允许调用线程修改线程组参数
        checkAccess();
        //调用本地挂起方法
        suspend0();
    }
    
    /**
     * 恢复一个挂起的线程。
     * 首先,调用此线程的checkaccess方法时不带参数。这可能导致抛出SecurityException(在当前线程中)。
     * 如果线程是活动的但挂起的,那么它将被恢复并允许在执行过程中取得进展。
     * @exception  SecurityException  如果当前线程无法修改此线程。
     * @see        #checkAccess
     * @see        #suspend()
     * @deprecated 此方法仅与@link suspend一起使用,
     *             该方法已被弃用,因为它容易死锁。
     */
    @Deprecated
    public final void resume() {
        checkAccess();
        resume0();
    }
    
    /**
     * 更改此线程的优先级。
     * 首先调用此线程的checkaccess方法,不带参数。这可能导致引发SecurityException
     * 否则,该线程的优先级将设置为指定的新优先级和线程线程组的最大允许优先级中的
     * 较小者。
     */
    public final void setPriority(int newPriority) {
        //声明线程组变量
        ThreadGroup g;
        //检查是否允许调用线程修改线程组参数
        checkAccess();
        //若新优先级超过限制,则抛出非法参数异常
        if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
            throw new IllegalArgumentException();
        }
        //若获取线程组不为空,且新优先级大于线程组的最大优先级
        //则将线程组的最大优先级赋给新优先级然后通过本地方法更改线程的优先级。 
        if((g = getThreadGroup()) != null) {
            if (newPriority > g.getMaxPriority()) {
                newPriority = g.getMaxPriority();
            }
            setPriority0(priority = newPriority);
        }
    }
    
    //返回该线程的优先级
    public final int getPriority() {
        return priority;
    }
    
    /**
     * 这是一个同步方法,用于设定线程名
     */
    public final synchronized void setName(String name) {
        //检查是否允许调用线程修改线程组参数
        checkAccess();
        //若参数为空则抛出空异常
        if (name == null) {
            throw new NullPointerException("name cannot be null");
        }
        //将本地名称变量设置为新名称参数
        this.name = name;
        //若线程状态不为新建
        if (threadStatus != 0) {
            //设置本地姓名变量
            setNativeName(name);
        }
    }
    
    //返回该线程的名称
    public final String getName() {
        return name;
    }
    
    //返回此线程所属的线程组。如果此线程已终止(已停止),则此方法返回空值。
    public final ThreadGroup getThreadGroup() {
        return group;
    }
    
    /**
     * 返回当前线程的线程组及其子组中活动线程数的估计值。
     * 递归迭代当前线程线程组中的所有子组。
     * 返回的值只是一个估计值,因为当此方法遍历内部数据结构时,线程数可能会动态更
     * 改,并且可能受某些系统线程的存在影响。
     * 此方法主要用于调试和监视目的。
     * 
     * @return 当前线程的线程组和任何其他以当前线程的线程组为祖先的线程组中活动线
     *         程数的估计值。
    public static int activeCount() {
        return currentThread().getThreadGroup().activeCount();
    }
    
    /**
     * 将当前线程的线程组及其子组中的每个活动线程复制到指定的数组中。此方法简单地
     * 调用当前线程的线程组的java.lang.ThreadGroup#enumerate(Thread[])的方法
     * 应用程序可能会使用activecount# activecount方法来估计数组的大小,
     * 但是如果数组太短,无法容纳所有线程,则会自动忽略多余的线程。如果获取当前线
     * 程的线程组及其子组中的每个活动线程至关重要,则调用程序应验证返回的int值是否
     * 严格小于tarray的长度。
     * 由于该方法固有的竞争条件,建议该方法仅用于调试和监视目的。
     * 
     * @param  tarray
     *         将线程列表放入其中的数组
     *
     * @return  放入数组的线程数
     *
     * @throws  SecurityException
     *          
     */
    public static int enumerate(Thread tarray[]) {
        return currentThread().getThreadGroup().enumerate(tarray);
    }
    
    /**
     * 统计此线程中的堆栈帧数。线程必须挂起。
     * @return 返回此线程中堆栈帧的数目。
     * @exception IllegalThreadStateException 如果这个线程没有挂起。
     * @deprecated 此调用的定义取决于@link suspend,这已被弃用。
     *             而且,这个调用的结果从未被很好地定义。
     */
    @Deprecated
    public native int countStackFrames();
    
    /**
     * 最多等待@code millis毫秒,此线程将停止。超时@code 0表示持续等待。
     * 此方法在实现上:循环调用以this.isAlive()方法为条件的wait()方法.
     * 当线程终止时notifyAll()方法会被调用.
     * 建议应用程序不要在thread实例上使用wait、notify或notifyall方法。
     * @param  millis
     *         等待时间(毫秒)
     * @throws  IllegalArgumentException
     *          如果@code millis的值为负数
     * @throws  InterruptedException
     *          如果有线程中断了当前线程。当抛出此异常时,
     *          当前线程的“中断状态”将被清除。
     */
     //加了同步锁
    public final synchronized void join(long millis)
    throws InterruptedException {
        //获取当前系统的毫秒值作为基数
        long base = System.currentTimeMillis();
        //初始化now变量为0
        long now = 0;
        //当入参毫秒值小于0则抛出非法参数异常
        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }
        //如果毫秒值为0,则当线程处于alive状态,则循环调用wait(0)方法
        if (millis == 0) {
            while (isAlive()) {
                wait(0);
            }
        } else {
        //毫秒值部位0,如果当前状态处于alive状态,循环执行等待时间直到处理时间小于
        //等于0跳出循环
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }
    
    //等待时间单位为纳秒,其它解释都和上面方法一样
    throws InterruptedException {

        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (nanos < 0 || nanos > 999999) {
            throw new IllegalArgumentException(
                                "nanosecond timeout value out of range");
        }

        if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
            millis++;
        }

        join(millis);
    }
    
    /**
     * 方法功能:等待一直到线程死亡.
     * 此方法的调用与调用的行为完全相同
     * @throws  InterruptedException
     *          如果有线程中断了当前线程。当抛出此异常时,
     *          当前线程的“中断状态”将被清除。
     */
    public final void join() throws InterruptedException {
        join(0);
    }
    
    //将当前线程的堆栈跟踪打印到标准错误流。此方法仅用于调试。
    public static void dumpStack() {
        new Exception("Stack trace").printStackTrace();
    }
    
    /**
  * 将当前线程设定为守护线程or用户线程.
  * 当运行的唯一线程都是守护进程线程时,Java虚拟机退出。
  * 此方法在start前被调用.
  * @param on 如果值为true,则此线程被设定为守护线程
  */
    public final void setDaemon(boolean on) {
        checkAccess();
        if (isAlive()) {
            throw new IllegalThreadStateException();
        }
        daemon = on;
    }
    
    //查看当前线程是否为守护线程
    public final boolean isDaemon() {
        return daemon;
    }
    
    /**
  * 确定当前运行的线程是否有权利更改此线程.
  * 如果有安全管理器,则会将当前线程作为参数传入checkAccess()方法.
  * 这可能会导致SecurityException异常的抛出.
  */
    public final void checkAccess() {
        SecurityManager security = System.getSecurityManager();
        if (security != null) {
            security.checkAccess(this);
        }
    }
    
    //线程转换为toString,格式包括 :线程名+优先级+所属组别
    public String toString() {
        ThreadGroup group = getThreadGroup();
        if (group != null) {
            return "Thread[" + getName() + "," + getPriority() + "," +
                           group.getName() + "]";
        } else {
            return "Thread[" + getName() + "," + getPriority() + "," +
                            "" + "]";
        }
    }
    
    /**
  * 此方法返回此线程的上下文类加载器.上下文类加载器由当加载类和资源时使用代码创建线程的创造者提供.
  * 如果通过方法setContextClassLoader进行上下文类加载器的设定,则默认的上下文类加载器为父线程.
  * 原始线程的类加载器通常被设定为:加载应用的类加载器.
  *
  * 如果安全管理器存在,且调用者的类加载器不为null,且它们不相同,且也不是父子关系,则此方法的调用会导致安全管理的SecurityManager#checkPermission(java.security.Permission) checkPermission方法。
  * checkPermission的调用,用于确定对上下文类加载器的检索是否被允许.
  *
  * 关于注解@CallerSensitive:这个注解是为了堵住漏洞用的。曾经有黑客通过构造双重反射来提升权限,原理是当时反射只检查固定深度的
  * 调用者的类,看它有没有特权.使用CallerSensitive后,getCallerClass不再用固定深度去寻找actual caller(“我”),而是把所
  * 有跟反射相关的接口方法都标注上CallerSensitive,搜索时凡看到该注解都直接跳过,这样就有效解决了这类的黑客问题.
  * @since 1.2
  */
    @CallerSensitive
    public ClassLoader getContextClassLoader() {
        if (contextClassLoader == null)
            return null;
        SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            ClassLoader.checkClassLoaderPermission(contextClassLoader,
                                                   Reflection.getCallerClass());
        }
        return contextClassLoader;
    }
    
    /**
  * 设定一个线程的上下文类加载器.上下文类加载器可以在线程被创建时被设定,且允许线程创建者提供合适的类加载器.
  *
  * 如果存在安全管理器,则它的checkPermission()方法会被调用,用于查看设定上下文类加载器的行为是否被允许.
  * @since 1.2
  */
    public void setContextClassLoader(ClassLoader cl) {
        SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            sm.checkPermission(new RuntimePermission("setContextClassLoader"));
        }
        contextClassLoader = cl;
    }
    
    
    /**
  * 当且仅当当前线程持有指定对象的监听器锁时,返回返回true.
  * 这一方法被设计的目的是:用于程序自身去声明它已经有某个对象的锁啦.
  * @since 1.4
  */
    public static native boolean holdsLock(Object obj);

    private static final StackTraceElement[] EMPTY_STACK_TRACE
        = new StackTraceElement[0];
    
    /**
  * 返回表示该线程堆栈转储的堆栈跟踪元素数组。
  * 如果线程还没有start,or虽然start了,但是并没有被CPU调用过,or线程以及终止了,则返回数组长度为0.
  * 如果返回数组长度非0,则数组中第一个元素(索引为0)代表了栈的顶部,就是所有调用方法中距离现在时间最近的那个.
  * 数组的最后一个元素代表了栈的底部,这是所有调用方法中距离现在时间最远的那个.
  *
  * 如果存在安全管理器,且这一线程又不是当前线程,则安全管理器的checkPermission()方法会被调用以查看
  *
  * 一些虚拟机在某些情况下,可能会在栈跟踪时遗漏至少一个以上的栈.在极端情况下,虚拟机没有任何栈跟踪信息所以返回数组长度为0.
  * @since 1.5
  */
    public StackTraceElement[] getStackTrace() {
        //如果此线程并不是当前线程
        if (this != Thread.currentThread()) {
            //检查getStackTrace许可情况.
            SecurityManager security = System.getSecurityManager();
            if (security != null) {
                security.checkPermission(
                    SecurityConstants.GET_STACK_TRACE_PERMISSION);
            }
            //if方法是一种优化,以便我们不会在此处调用虚拟机里面还没有开始或者已经死亡的线程.
            if (!isAlive()) {
                return EMPTY_STACK_TRACE;
            }
            StackTraceElement[][] stackTraceArray = dumpThreads(new Thread[] {this});
            StackTraceElement[] stackTrace = stackTraceArray[0];
            //在前面的isAlive检查中一个活着的线程可能在此时已经终结了,所以此时不会再有栈跟踪.
            if (stackTrace == null) {
                stackTrace = EMPTY_STACK_TRACE;
            }
            return stackTrace;
        } else {
            //此处并不需要JVM的帮忙.
            return (new Exception()).getStackTrace();
        }
    }
    
    /**
  * 返回一个用于所有存活线程的栈跟踪信息的map.
  * map的key是每个线程;value是对应线程的栈跟踪元素的一个数组.
  *
  * 当此方法被调用时,可能有些线程正在执行.每一个线程的栈跟踪信息都代表了线程在某一时刻状态的快照且每一个栈跟踪信息
  * 会在不同的时间得到.如果虚拟机中某一个线程没有栈跟踪信息则其数组长度为0.
  *
  * 如果有安全管理器,则安全管理器的checkPermission方法会被调用以检查是否允许获取所有线程的栈跟踪信息.
  *
  * @since 1.5
  */
    public static Map<Thread, StackTraceElement[]> getAllStackTraces() {
        //检查getStackTrace许可情况.
        SecurityManager security = System.getSecurityManager();
        if (security != null) {
            security.checkPermission(
                SecurityConstants.GET_STACK_TRACE_PERMISSION);
            security.checkPermission(
                SecurityConstants.MODIFY_THREADGROUP_PERMISSION);
        }

        //获取一个所有线程的列表的一个快照
        Thread[] threads = getThreads();
        StackTraceElement[][] traces = dumpThreads(threads);
        Map<Thread, StackTraceElement[]> m = new HashMap<>(threads.length);
        for (int i = 0; i < threads.length; i++) {
            StackTraceElement[] stackTrace = traces[i];
            if (stackTrace != null) {
                m.put(threads[i], stackTrace);
            }
            // 否则就终止了所以我们不把它放到Map里
        }
        return m;
    }
    
    //常量:运行时许可
    private static final RuntimePermission SUBCLASS_IMPLEMENTATION_PERMISSION =
                    new RuntimePermission("enableContextClassLoaderOverride");
                    
    //子类安全审核结果的缓存
  //在将来如果它出现的话,可以替代ConcurrentReferenceHashMap
    private static class Caches {
        //子类安全审核结果的缓存值
        static final ConcurrentMap<WeakClassKey,Boolean> subclassAudits =
            new ConcurrentHashMap<>();
        //审核子类的弱引用队列
        static final ReferenceQueue<Class<?>> subclassAuditsQueue =
            new ReferenceQueue<>();
    }
    
    
    /**
  * 证明是否可以在不违反安全约束的情况下构造此(可能是子类)实例:子类不能覆盖安
  * 全敏感,非final类型的方法,否则将检查“EnableContextClassLoaderOverride”运行时
  * 权限。
  */
    private static boolean isCCLOverridden(Class<?> cl) {
        //如果传入的时Thread类或子类直接返回false
        if (cl == Thread.class)
            return false;
        //不太清楚这里的代码
        processQueue(Caches.subclassAuditsQueue, Caches.subclassAudits);
        WeakClassKey key = new WeakClassKey(cl, Caches.subclassAuditsQueue);
        Boolean result = Caches.subclassAudits.get(key);
        if (result == null) {
            result = Boolean.valueOf(auditSubclass(cl));
            Caches.subclassAudits.putIfAbsent(key, result);
        }

        return result.booleanValue();
    }
    
    // 对给定的子类执行反射检查,以验证它是否重写安全敏感的非final方法。如果子类
    // 重写任何方法,则返回true,否则返回false。
    private static boolean auditSubclass(final Class<?> subcl) {
        Boolean result = AccessController.doPrivileged(
            new PrivilegedAction<Boolean>() {
                public Boolean run() {
                    for (Class<?> cl = subcl;
                         cl != Thread.class;
                         cl = cl.getSuperclass())
                    {
                        try {
                            cl.getDeclaredMethod("getContextClassLoader", new Class<?>[0]);
                            return Boolean.TRUE;
                        } catch (NoSuchMethodException ex) {
                        }
                        try {
                            Class<?>[] params = {ClassLoader.class};
                            cl.getDeclaredMethod("setContextClassLoader", params);
                            return Boolean.TRUE;
                        } catch (NoSuchMethodException ex) {
                        }
                    }
                    return Boolean.FALSE;
                }
            }
        );
        return result.booleanValue();
    }
    
    //本地方法,往堆栈压入线程组,返回堆栈深度数据
    private native static StackTraceElement[][] dumpThreads(Thread[] threads);
    //本地方法获取线程组
    private native static Thread[] getThreads();
    
    
    /**
  * 返回当前线程的ID.
  * 线程ID是一个long类型的正数,在线程被创建时就有的.
  * 线程ID在其生命周期内都不会更改且独一无二.
  * 当线程终止时,则此线程的ID会被重复使用.
  * @since 1.5
  */
    public long getId() {
        return tid;
    }
    
    /**
  * 此枚举表示线程状态.线程状态有如下几种:
  * 1.NEW表示:线程还未开始,只是进行了一些线程创建的初始化操作,但未调用start()方法.
  * 2.RUNNABLE表示:线程在JVM里面处于运行状态(这里就绪和运行同属于运行).
  * 3.BLOCKED表示:线程正在等待一个监视器锁,处于阻塞状态.
  * 4.WAITING表示:一个线程在等待另一个线程的特定操作(通知or中断),这种等待是无限期的.
  * 5.TIMED_WAITING表示:一个线程在等待另一个线程的特定操作,这种等待是有时间限制的.一旦超时则线程自行返回.
  * 6.TERMINATED表示:线程已退出.表示线程已经执行完毕.
  *
  * 线程在某一时刻,只能处于上述6个状态的某一个.这些状态值是虚拟机状态值,因而并不会反映操作系统的线程状态.
  *
  * @since 1.5
  * @see #getState
  */
  public enum State {
  //尚未启动的线程的线程状态。
  NEW,
  //线程可以正在运行,也可以处于就绪状态等待获得CPU.
  //Running为获取到了CPU时间片的状态,人为增加的一种状态,不在官方状态声明之中
  RUNNABLE,
  //线程的线程状态被阻止,正在等待监视器锁。
  //在调用完wait()方法后,处于阻塞状态的线程正在等待监视器锁进入同步块/方法,
  //或在调用对象后重新输入同步块/方法。为了进入同步方法(锁)或重进入同步方法(锁)
  BLOCKED,
  /**
  * 等待线程的线程状态。
  * 一个线程处于wating状态,是因为调用了下面方法中的某一个:
  * 1.Object.wait 没有超时
  * 2.Thread.join 没有超时
  * 3.LockSupport.park
  *
  * 处于等待状态的线程正在等待另一个线程执行特定操作。
  * 其它线程的特定操作包括 :notify(),notifyAll(),join()等.
   * 例如,一个在对象上调用了object.wait()的线程正在等待另一个线程在该对象上调
   * 用object.notify()或object.notifyAll()。调用thread.join()的线程正在等
   * 待指定的线程终止。
  */
  WAITING,
  /**
  * 具有指定等待时间的等待线程的线程状态。
  * 由于使用指定的正等待时间调用以下方法之一,线程处于正等待状态:
  * 1.Thread.sleep()
  * 2.Object.wait()
  * 3.Thread.join()
  * 4.LockSupport.parkNanos()
  * 5.LockSupport.parkUntil()
  */
  TIMED_WAITING,
  
  //终止线程的线程状态。
  //线程完成了执行
  TERMINATED;

  }
  
  /**
   * 返回此线程的状态。
     * 此方法设计用于监视系统状态,而不是同步控制。
     * @return 这个线程的状态.
     * @since 1.5
  public State getState() {
        // get current thread state
        return sun.misc.VM.toThreadState(threadStatus);
    }
    // Added in JSR-166
    /**
  * 由于未捕获异常而导致线程终止的函数接口处理器.
  * 当一个线程由于未捕获异常而终止时,JVM将会使用getUncaughtExceptionHandler来查询此线程的UncaughtExceptionHandler,
  * 且会调用处理器handler的uncaughtException()方法,将此线程和其异常作为参数.
  *
  * 如果一个线程没有它特定的UncaughtExceptionHandler,则它所属的线程组对象充当其UncaughtExceptionHandler.
  * 如果线程组对象没有处理异常的指定请求,它可以向前调用getDefaultUncaughtExceptionHandler的默认处理异常的方法.
  *
  * @see #setDefaultUncaughtExceptionHandler
  * @see #setUncaughtExceptionHandler
  * @see ThreadGroup#uncaughtException
  * @since 1.5
  */
    @FunctionalInterface
    public interface UncaughtExceptionHandler {
        /**
       * 由于未捕获异常而导致线程终止的方法调用.
         * 此方法抛出的任何异常都会被JVM忽略.
       * @param t the thread
       * @param e the exception
       */
        void uncaughtException(Thread t, Throwable e);
    }
    
    //除非显式设置,否则为空
    private volatile UncaughtExceptionHandler uncaughtExceptionHandler;
    //除非显式设置,否则为空
    private static volatile UncaughtExceptionHandler defaultUncaughtExceptionHandler;
    
    /**
  * 设定默认处理器用于处理:由于未捕获异常而导致的线程终止,且此线程还未定义任何其它的处理器.
  *
  * 未捕获异常首先由本线程进行处理,然后由线程所属的线程组对象处理,最后由默认未捕获异常处理器进行处理.
  * 如果线程未设定明确的未捕获异常处理器,且线程的线程组(包括父线程组)也未指定,则此时默认处理器的uncaughtException
  * 方法会被执行.由于设定了默认的未捕获异常处理器,则应用能够更改未捕获异常的处理方法.
  *
  * 注意:默认的未捕获异常处理器不应该经常使用线程的线程组对象,因为这会引起无限递归.
  *
  * @since 1.5
  */
    public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler eh) {
        SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            sm.checkPermission(
                new RuntimePermission("setDefaultUncaughtExceptionHandler")
                    );
        }
         defaultUncaughtExceptionHandler = eh;
    }
    
    /**
     * 返回当线程因未捕获的异常而突然终止时调用的默认处理程序。如果返回值为空,
     * 则没有默认值。
     * @since 1.5
     * @see #setDefaultUncaughtExceptionHandler
     * @return the default uncaught exception handler for all threads
     */
    public static UncaughtExceptionHandler getDefaultUncaughtExceptionHandler(){
        return defaultUncaughtExceptionHandler;
    }
    
    //返回当此线程由于未捕获的异常而突然终止时调用的处理程序。
    //如果该线程没有显式设置未捕获的异常处理程序,则返回该线程的ThreadGroup对象,
    //除非该线程已终止,在这种情况下返回空值。
    public UncaughtExceptionHandler getUncaughtExceptionHandler() {
        return uncaughtExceptionHandler != null ?
            uncaughtExceptionHandler : group;
    }
    
    /**
  * 设定一个由于未捕获异常而导致线程中断的处理器.
  * 通过设定未捕获异常处理器,一个线程可以完全控制如何处理未捕获异常.
  * 如果没有设定未捕获异常,则线程组对象默认为其未捕获异常处理器.
  * @since 1.5
  */
    public void setUncaughtExceptionHandler(UncaughtExceptionHandler eh) {
        checkAccess();
        uncaughtExceptionHandler = eh;
    }
    
    //将未捕获异常分发给处理器.这一方法通常被JVM调用.
    private void dispatchUncaughtException(Throwable e) {
        getUncaughtExceptionHandler().uncaughtException(this, e);
    }
    
    //从指定的映射中删除已在指定引用队列中排队的任何键。
    static void processQueue(ReferenceQueue<Class<?>> queue,
                             ConcurrentMap<? extends
                             WeakReference<Class<?>>, ?> map)
    {
        Reference<? extends Class<?>> ref;
        while((ref = queue.poll()) != null) {
            map.remove(ref);
        }
    }
    
    /**
  * Weak key for Class objects.
  * WeakReference类说明:弱引用对象(JVM四种引用中的弱引用),这并不妨碍它们的引用对象被最终化、定型,然后回收.弱引用最常用于实现规范化映射。
  **/
    static class WeakClassKey extends WeakReference<Class<?>> {
        //用于保存引用的参照hash值,一旦参照明确后用于保持一个持续的hash值.
        private final int hash;

        //根据给定的对象创建一个weakClassKey,使用给定队列进行注册.
        WeakClassKey(Class<?> cl, ReferenceQueue<Class<?>> refQueue) {
            super(cl, refQueue);
            hash = System.identityHashCode(cl);
        }

        //返回原始引用的参照hash值
        @Override
        public int hashCode() {
            return hash;
        }

        /**
         * 如果给定对象是此相同的weakclassky实例,或者如果尚未清除此对象的引用,
         * 如果给定对象是另一个与此对象具有相同的非空引用的weakclassky实例,
         * 则返回true。
         */
        @Override
        public boolean equals(Object obj) {
            if (obj == this)
                return true;

            if (obj instanceof WeakClassKey) {
                Object referent = get();
                return (referent != null) &&
                       (referent == ((WeakClassKey) obj).get());
            } else {
                return false;
            }
        }
    }
    
    /**
  * 以下三个初始未初化的变量专门由java.util.concurrent.ThreadLocalRandom管理.
  * 这些变量用在并发代码中构建高性能的PRNGs,由于存在共享失败的情况所以我们不能冒险共享.
  * 因此,这些变量和注解@Contended是隔离的.
  */
    //用于ThreadLocalRandom的当前种子
    @sun.misc.Contended("tlr")
    long threadLocalRandomSeed;

    //探测hash值;如果threadLocalRandomSeed已经初始化了,则其值非0
    @sun.misc.Contended("tlr")
    int threadLocalRandomProbe;

    //隔离ThreadLocalRandom序列的第二个种子
    @sun.misc.Contended("tlr")
    int threadLocalRandomSecondarySeed;

    //一些私有本地辅助方法
    private native void setPriority0(int newPriority);
    private native void stop0(Object o);
    private native void suspend0();
    private native void resume0();
    private native void interrupt0();
    private native void setNativeName(String name);
}

线程状态及生命周期演化图

Hotspot源码路径hotspot/src/share/vm/classfile/javaClasses.hpp中寻找线程状态整型值:

线程状态 整型值 解释
新建(NEW) 0 刚刚创建,尚未启动(未调用start()方法)的线程处于此状态
运行(RUNNABLE) 5 Java线程中将就绪(ready)和运行中(running)两种状态笼统的称为“运行”。
线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。
该状态的线程位于可运行线程池中,等待被线程调度选中,获取CPU的使用权,此时处于就绪状态。
就绪状态的线程在获得CPU时间片后变为运行中状态(running)。
阻塞(BLOCKED) 1025 表示线程阻塞于锁。
等待(WAITING) 401 进入该状态的线程需要等待其他线程做出一些特定动作(通知或中断)。
限时等待(TIMED_WAITING) 417 该状态不同于WAITING,它可以在指定的时间后自行返回。
终止(TERMINATED) 2 表示该线程已经执行完毕。

等待通知相关方法:
等待/通知的相关方法是任意Java对象都具备的,因为这些方法被定义在所有对象的超类
java.lang.Object上

方法名称 描述
notify() 通知一个在对象上等待的线程,使其从wait()方法返回,而返回的前提是该线程获取到了对象的锁1
notifyAll() 通知所有等待在该对象上的对象
wait() 调用该方法的线程进入WAITING状态,只有等待另外线程的通知或被中断才会返回,需要注意,调用wait()后,会释放对象的锁
wait(long) 超时等待一段时间,这里的参数时间是毫秒,也就是等待长达n毫秒,如果没有通知就超时返回
wait(long, int) 对于超时时间更细粒度的控制,可以达到纳秒

等待/通知机制,是指一个线程A调用了对象O的wait()方法进入等待状态,而另一个线程B调用了对象O的notify()或者notifyAll()方法,线程A收到通知后从对象O的wait()方法返回,进而执行后续操作。上述两个线程通过对象O来完成交互,而对象上的wait()和notify/notifyAll()的关系就如同开关信号一样,用来完成等待方和通知方之间的交互工作。

线程生命周期演化图

  • 线程分配到的时间片多少也就决定了线程使用处理器资源的多少,而线程优先级就是决定线程需要多或者少分配一些处理器资源的线程属性。线程优先级不能作为程序正确性的依赖,因为操作系统可以完全不用理会Java线程对于优先级的设定。
  • 当线程执行wait()方法之后,线程进入等待状态。进入等待状态的线程需要依靠其他线程的通知才能够返回到运行状态,而超时等待状态相当于在等待状态的基础上增加了超时限制,也就是超时时间到达时将会返回到运行状态。当线程调用同步方法时,在没有获取到锁的情况下,线程将会进入到阻塞状态。线程在执行Runnable的run()方法之后将会进入到终止状态。
  • Java将操作系统中的运行和就绪两个状态合并称为运行状态。阻塞状态是线程阻塞在进入synchronized关键字修饰的方法或代码块(获取锁)时的状态,但是阻塞在java.concurrent包中Lock接口的线程状态却是等待状态,因为java.concurrent包中Lock接口对于阻塞的实现均使用了LockSupport类中的相关方法。
  • 每当线程调度器有机会选择新线程时, 它首先选择具有较高优先级的线程。但是,线程优先级是高度依赖于系统的。当虚拟机依赖于宿主机平台的线程实现机制时, Java 线程的优先级被映射到宿主机平台的优先级上, 优先级个数也许更多,也许更少。Windows 有7 个优先级别。一些Java 优先级将映射到相同的操作系统优先级。在Oracle 为Linux 提供的Java 虚拟机中,线程的优先级被忽略一所有线程具有相同的优先级。
发布了5 篇原创文章 · 获赞 3 · 访问量 8340
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章