多线程——Thread(包括sleep是否会占用CPU资源验证)

一、简单使用

@Test
	public void ThreadTest() throws InterruptedException  {
		Thread thread = new Thread(new Runnable() {
			
			@Override
			public void run() {
				System.out.println("开启线程名称  :"+Thread.currentThread().getName());
			}
		});
		thread.start();
		System.out.println("主线程名称:"+Thread.currentThread().getName());
		Thread.sleep(100);
	}

运行效果:
在这里插入图片描述

二、源码

Ⅰ、类说明

  1. 一个 thread 是程序中的执行线程,Java 虚拟机允许一个应用同时执行多个线程
  2. 每一个线程都有一个优先级。具有较高优先级的线程优先于较低优先级的线程执行
  3. 每个线程可能会,也可能不会被标记为一个守护程序(daemon)
  4. 当在某个线程中运行的代码创建性的 Thread 对象时,新线程的优先级最初设置为等于创建线程的有限即,若创建的线程是 一个守护线程,那么被创建的线程也是一个守护线程(说白了,新线程的优先级、是否为守护线程 就是“子随父”)
  5. 当 Java 虚拟机启动时,通常有一个非守护线程(通常调用指定类的 main 方法),Java 虚拟机继续执行直到发生以下任何一种情况:
    ① 调用类 Runtime 的 exit方法,并且安全管理器已允许进行退出操作
    ② 所有的非守护线程都已经消亡,要么通过调用返回到 run 方法,要么抛出传播到 run 方法之外的异常(注意:这里指的是个线程抛出异常,其它线程捕获异常,与我们平时在编码时的同一线程内是不一样的)
  6. 这里有两种方式去创建一个新的线程执行。第一种方式是声明一个类成为 Thread 的子类,这个子类应该重写 run 方法第二种方式是声明一个类,并实现 Runnable 接口,然后这个类实现 run 方法
  7. 每个线程都有一个名字供识别,一个以上的线程可能具有相同的名称。如果在创建线程时未指定名称,则会为其生成一个新的名称
  8. 除非另有说明,否则将 null 参数传递给此类(这里特指 Thread)中的构造函数或方法将引发空指针异常

Ⅱ、类结构说明

在这里插入图片描述

Ⅲ、属性声明

    /* Make sure registerNatives is the first thing <clinit> does. */
    //确保 registerNatives 是第一件要做的事情(看命名可以推测,应当是本地注册,这里使用了 native 修饰符)
    private static native void registerNatives();
    static {
        registerNatives();
    }

    private volatile String name;  	//线程名
    private int            priority; //优先级
    private Thread         threadQ;  // 这个我还没找到关于它的资料说明
    private long           eetop;   // 这个我还没找到关于它的资料说明

    /* Whether or not to single_step this thread. */
    // 是否单步执行此线程,怎么用未知?
    private boolean     single_step;

    /* Whether or not the thread is a daemon thread. */
    //线程是否为守护线程
    private boolean     daemon = false;

    /* JVM state */
    //JVM 状态
    private boolean     stillborn = false;

    /* What will be run. */
    //将要运行的内容
    private Runnable target;

    /* The group of this thread */
    //这个线程所属的线程组
    private ThreadGroup group;

    /* The context ClassLoader for this thread */
    // 线程的上下文加载器
    private ClassLoader contextClassLoader;

    /* The inherited AccessControlContext of this thread */
    // 这个线程继承的 AccessControlContext (访问控制上下文对象)
    private AccessControlContext inheritedAccessControlContext;

    /* For autonumbering anonymous threads. */
    //用于自动编号匿名线程
    private static int threadInitNumber;
    private static synchronized int nextThreadNum() {
        return threadInitNumber++;
    }

    /* ThreadLocal values pertaining to this thread. This map is maintained
     * by the ThreadLocal class. */
    //与此线程有关的 ThreadLocal值 该映射由 ThreadLocal 类维护
    ThreadLocal.ThreadLocalMap threadLocals = null;

    /*
     * InheritableThreadLocal values pertaining to this thread. This map is
     * maintained by the InheritableThreadLocal class.
     */
     //与此线程有关的 InheritableThreadLocal 值,该映射由InheritableThreadLocal 类维护
    ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;

    /*
     * The requested stack size for this thread, or 0 if the creator did
     * not specify a stack size.  It is up to the VM to do whatever it
     * likes with this number; some VMs will ignore it.
     */
     // 此线程请求的堆栈大小,如果创建者未指定堆栈大小,则为0.由虚拟机决定使用此编号执行任何操作。
     //一些虚拟机将忽略它
    private long stackSize;

    /*
     * JVM-private state that persists after native thread termination.
     */
     // JVM私有状态在本地线程终止后仍然存在
    private long nativeParkEventPointer;

    /*
     * Thread ID
     */
     //线程id 
    private long tid;

    /* For generating thread ID */
    // 用于生成线程 id
    private static long threadSeqNumber;

    /* Java thread status for tools,
     * initialized to indicate thread 'not yet started'
     */
    // Java 线程状态工具,初始化后指示线程“尚未启动”
    private volatile int threadStatus = 0;


    private static synchronized long nextThreadID() {
        return ++threadSeqNumber;
    }

    /**
     * The argument supplied to the current call to
     * java.util.concurrent.locks.LockSupport.park.
     * Set by (private) java.util.concurrent.locks.LockSupport.setBlocker
     * Accessed using java.util.concurrent.locks.LockSupport.getBlocker
     */
     // 提供给 java.util.concurrent.locks.LockSupport.park. 的当前调用的参数
     // 由私有 java.util.concurrent.locks.LockSupport.setBlocker 设置
     // 使用 java.util.concurrent.locks.LockSupport.getBlocker 访问
    volatile Object parkBlocker;

    /* The object in which this thread is blocked in an interruptible I/O
     * operation, if any.  The blocker's interrupt method should be invoked
     * after setting this thread's interrupt status.
     */
     //在可中断的I/O操作中阻塞该线程的对象(如果有),设置此线程的中断状态后,应调用阻塞程序的中断方法
    private volatile Interruptible blocker;
    private final Object blockerLock = new Object();

    /* Set the blocker field; invoked via sun.misc.SharedSecrets from java.nio code
     */
     //设置阻止字段;通过 java.nio 代码中的 sun.misc.SharedSecrets
    void blockedOn(Interruptible b) {
        synchronized (blockerLock) {
            blocker = b;
        }
    }

    /**
     * The minimum priority that a thread can have.
     */
     //线程拥有的最低优先级
    public final static int MIN_PRIORITY = 1;

   /**
     * The default priority that is assigned to a thread.
     */
     //线程默认优先级
    public final static int NORM_PRIORITY = 5;

    /**
     * The maximum priority that a thread can have.
     */
     //线程最高优先级
    public final static int MAX_PRIORITY = 10;

Ⅳ、Thread 内的方法和内部类说明

/**
     * Returns a reference to the currently executing thread object.
     *
     * @return  the currently executing thread.
     */
     // 返回当前执行线程对象的引用
    public static native Thread currentThread();
/**
     * A hint to the scheduler that the current thread is willing to yield
     * its current use of a processor. The scheduler is free to ignore this
     * hint.
     *
     * <p> Yield is a heuristic attempt to improve relative progression
     * between threads that would otherwise over-utilise a CPU. Its use
     * should be combined with detailed profiling and benchmarking to
     * ensure that it actually has the desired effect.
     *
     * <p> It is rarely appropriate to use this method. It may be useful
     * for debugging or testing purposes, where it may help to reproduce
     * bugs due to race conditions. It may also be useful when designing
     * concurrency control constructs such as the ones in the
     * {@link java.util.concurrent.locks} package.
     */
     /**
     * 给调度程序提示,当前线程愿意放弃当前使用的处理器,调度程序可以随意忽略此提示
     * Yield 是一种启发式尝试,旨在提高线程之间的执行,否则将过渡利用 CPU。 因将其使用的性能分析和基准测试结合起来
     * 已确保它实际上具有所需的效果。
     * 很少适合使用此方法。对于调式或测试目的,它可能有用,因为它可能有助于重现由于竞争条件而产生的错误。当设计者
     * 诸如 java.util.concurrent.locks 包中的并发控制结构时,它也可能很有用
     * 说白了,这个方法就是主动让出 CPU 资源,但是需要注意的是:在让出CPU资源后,仍有可能再次执行这个线程
     */
    public static native void yield();
/**
     * Causes the currently executing thread to sleep (temporarily cease
     * execution) for the specified number of milliseconds, subject to
     * the precision and accuracy of system timers and schedulers. The thread
     * does not lose ownership of any monitors.
     *
     * @param  millis
     *         the length of time to sleep in milliseconds
     *
     * @throws  IllegalArgumentException
     *          if the value of {@code millis} is negative
     *
     * @throws  InterruptedException
     *          if any thread has interrupted the current thread. The
     *          <i>interrupted status</i> of the current thread is
     *          cleared when this exception is thrown.
     */
     /**
     * 线程睡眠,这个比较常用,需要注意:
     * 1.单位是毫秒
     * 2.不会失去锁
     * 3.yield 会放弃 CPU 资源吗,那 sleep 会放弃 CPU 资源吗? 出于好奇,做了一个小实验,如下:
     */
    public static native void sleep(long millis) throws InterruptedException;
关于 sleep 是否会放弃CPU资源的小实验:

为了效果明显,对多个线程同时操作
① 创建多个线程,使它们同时执行 sleep 方法 ,查看程序的线程数以及CPU
第一次执行代码如下:

	@Test
	public void ThreadTest() throws InterruptedException  {
		for(int i = 0; i < 40; i++) {
			Thread thread = new Thread(new Runnable() {
				@Override
				public void run() {
					System.out.println("开启线程名称  :"+Thread.currentThread().getName());
					try {
						Thread.sleep(30*1000);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			});
			thread.start();
		}
		System.out.println("主线程名称:"+Thread.currentThread().getName());
		long start = System.currentTimeMillis();
		long end = start;
		long time = start - end;
		while(time < 40*1000 ) {
			end = System.currentTimeMillis();
			time = end -start;
		}
	
	}

结果如下: sleep 后 CPU 使用情况并不高,程序中的线程确实是存在的
在这里插入图片描述
② 创建和第一次实验一样多的线程,只使其中一半线程 sleep ,另一半处于运行状态:
实验代码如下:

@Test
	public void ThreadTest() throws InterruptedException  {
		for(int i = 0; i < 20; i++) {
			Thread thread = new Thread(new Runnable() {
				@Override
				public void run() {
					System.out.println("开启线程名称  :"+Thread.currentThread().getName());
					try {
						Thread.sleep(30*1000);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			});
			thread.start();
		}
		for(int i = 0; i < 20; i++) {
			Thread thread = new Thread(new Runnable() {
				@Override
				public void run() {
					System.out.println("开启线程名称  :"+Thread.currentThread().getName());
					try {
						long start = System.currentTimeMillis();
						long end = start;
						long time = end - start;
						while(time < 30*1000 ) {
							end = System.currentTimeMillis();
							time = end -start;
						}
					} catch (Exception e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			});
			thread.start();
		}
		System.out.println("主线程名称:"+Thread.currentThread().getName());
		long start = System.currentTimeMillis();
		long end = start;
		long time = start - end;
		while(time < 40*1000 ) {
			end = System.currentTimeMillis();
			time = end -start;
		}
	
	}
	

第二次实验结果如下: 可以看到 CPU 在一定区间内上升到 100%,
在这里插入图片描述
问题分析:

第一次第二次
CPU使用情况基本稳定在 12%运行程序后CPU迅速飙升
开启线程数量40个线程全都调用sleep方法40个线程(20个线程调用sleep方法,20个线程在30秒内空轮询占用 CPU资源)

由实验对比可以得到结论,使用 sleep 的线程并不会去占用 CPU 资源 ,因为如果 sleep 占用 CPU 资源的话,第一次实验的CPU占用率不可能

实验完成,继续跟着源码,一点点的往下看:

    /**
     * Initializes a Thread.   初始化一个线程
     *
     * @param g the Thread group    线程组,线程组代表一组线程,此外线程组还可以包括其它线程组。线程组形成一个树,除了初始线程组外,每
     * 个线程组都会有一个父进程
     * @param target the object whose run() method gets called run方法被调用的目标对象
     * @param name the name of the new Thread  新线程的名称
     * @param stackSize the desired stack size for the new thread, or  //栈大小
     *        zero to indicate that this parameter is to be ignored.
     * @param acc the AccessControlContext to inherit, or   //访问控制上下文对象
     *            AccessController.getContext() if null
     * @param inheritThreadLocals if {@code true}, inherit initial values for
     *            inheritable thread-locals from the constructing thread
     */
    private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize, AccessControlContext acc,
                      boolean inheritThreadLocals) {
        if (name == null) { //线程名为空 抛出空指针异常
            throw new NullPointerException("name cannot be null");
        }

        this.name = name;

        Thread parent = currentThread();
        SecurityManager security = System.getSecurityManager(); //获取安全管理对象,这个在集合里面也有,我还没研究过这个对象
        if (g == null) { //如果线程组为空 
            /* Determine if it's an applet or not */  //确定它是否使一个小程序

            /* If there is a security manager, ask the security manager
               what to do. */
            if (security != null) { //如果 安全管理对象不为空
                g = security.getThreadGroup();  //获取安全管理对象所在线程组对象,并赋给 g
            }

            /* If the security doesn't have a strong opinion of the matter
               use the parent thread group. */
            if (g == null) { //如果g 为空,
                g = parent.getThreadGroup(); //获取父线程对象所在的线程组对象,并赋给 g
            }
        }

        /* checkAccess regardless of whether or not threadgroup is
           explicitly passed in. */
        //不管是否显示传递线程组,都应该使用 checkAccess
        g.checkAccess();

        /*
         * Do we have the required permissions?
         */
         //我们具有所需要的权限吗?
        if (security != null) {
            if (isCCLOverridden(getClass())) {
                security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
            }
        }
        //增加线程组中未启动线程的数量。未启动的线程不会添加到线程组中,这样即使从未启动过的线程也不会被收集,但
        //是必须对它们进行计数,以便不会破坏其中从未启动的线程的守护程序线程组
        g.addUnstarted(); 
        
        this.group = g;
        this.daemon = parent.isDaemon();
        this.priority = parent.getPriority();
        if (security == null || isCCLOverridden(parent.getClass()))
            this.contextClassLoader = parent.getContextClassLoader();
        else
            this.contextClassLoader = parent.contextClassLoader;
        this.inheritedAccessControlContext =
                acc != null ? acc : AccessController.getContext();
        this.target = target;
        setPriority(priority);
        if (inheritThreadLocals && parent.inheritableThreadLocals != null)
            this.inheritableThreadLocals =
                ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
        /* Stash the specified stack size in case the VM cares */
        this.stackSize = stackSize;

        /* Set thread ID */
        tid = nextThreadID();
    }
//Thread 不支持克隆,会抛出克隆不支持异常,这个了解一下就好了
/**
     * Throws CloneNotSupportedException as a Thread can not be meaningfully
     * cloned. Construct a new Thread instead.
     *
     * @throws  CloneNotSupportedException
     *          always
     */
    @Override
    protected Object clone() throws CloneNotSupportedException {
        throw new CloneNotSupportedException();
    }
/**
     * Allocates a new {@code Thread} object. This constructor has the same
     * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
     * {@code (null, null, gname)}, where {@code gname} is a newly generated
     * name. Automatically generated names are of the form
     * {@code "Thread-"+}<i>n</i>, where <i>n</i> is an integer.
     */
     // Thread 构造方法,只需了解一下调用 init 方法传的参数就好
    public Thread() {
        init(null, null, "Thread-" + nextThreadNum(), 0);
    }

    /**
     * Allocates a new {@code Thread} object. This constructor has the same
     * effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
     * {@code (null, target, gname)}, where {@code gname} is a newly generated
     * name. Automatically generated names are of the form
     * {@code "Thread-"+}<i>n</i>, where <i>n</i> is an integer.
     *
     * @param  target
     *         the object whose {@code run} method is invoked when this thread
     *         is started. If {@code null}, this classes {@code run} method does
     *         nothing.
     */
     // Thread 构造方法,只需了解一下调用 init 方法传的参数就好
    public Thread(Runnable target) {
        init(null, target, "Thread-" + nextThreadNum(), 0);
    }
    ... //一堆构造方法
 /**
     * Causes this thread to begin execution; the Java Virtual Machine
     * calls the <code>run</code> method of this thread.
     * <p>
     * The result is that two threads are running concurrently: the
     * current thread (which returns from the call to the
     * <code>start</code> method) and the other thread (which executes its
     * <code>run</code> method).
     * <p>
     * It is never legal to start a thread more than once.
     * In particular, a thread may not be restarted once it has completed
     * execution.
     *
     * @exception  IllegalThreadStateException  if the thread was already
     *               started.
     * @see        #run()
     * @see        #stop()
     */
     /**
     * 使该线程开始执行,Java 虚拟机调用这个线程的 run 方法
     * 执行结果是两个线程正常运行:当前线程(指调用 start 方法的这个线程)和另一个线程(执行 run 方法的线程)
     * 一个线程启动多次是不合法的,特别是执行完成后的线程,无法被重新启动(这个大家可以自己去验证下,就6行代码)
     */
    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".
         */
         //对于虚拟机创建/设置的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.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
                /* do nothing. If start0 threw a Throwable then
                  it will be passed up the call stack */
            }
        }
    }
/**
     * If this thread was constructed using a separate
     * <code>Runnable</code> run object, then that
     * <code>Runnable</code> object's <code>run</code> method is called;
     * otherwise, this method does nothing and returns.
     * <p>
     * Subclasses of <code>Thread</code> should override this method.
     *
     * @see     #start()
     * @see     #stop()
     * @see     #Thread(ThreadGroup, Runnable, String)
     */
     //如果该线程是使用单独的 Runnable 运行对象构造的,则调用 Runnale 对象的 run 方法;否则,此方法不执行任何操作
     //并返回。 Thread 的子类应该重写这个方法
    @Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }
/**
     * This method is called by the system to give a Thread
     * a chance to clean up before it actually exits.
     */
     //系统调用此方法,使线程有机会在线程退出之前进行清理
    private void exit() {
        if (group != null) {
            group.threadTerminated(this); //通知线程组,这个线程已经终止了
            group = null;
        }
        /* Aggressively null out all reference fields: see bug 4006245 */
        //积极清空所有参考字段
        target = null;
        /* Speed the release of some of these resources */
        //加快资源释放
        threadLocals = null;
        inheritableThreadLocals = null;
        inheritedAccessControlContext = null;
        blocker = null;
        uncaughtExceptionHandler = null;
    }
    /**
     * Forces the thread to stop executing.
     * <p>
     * If there is a security manager installed, its <code>checkAccess</code>
     * method is called with <code>this</code>
     * as its argument. This may result in a
     * <code>SecurityException</code> being raised (in the current thread).
     * <p>
     * If this thread is different from the current thread (that is, the current
     * thread is trying to stop a thread other than itself), the
     * security manager's <code>checkPermission</code> method (with a
     * <code>RuntimePermission("stopThread")</code> argument) is called in
     * addition.
     * Again, this may result in throwing a
     * <code>SecurityException</code> (in the current thread).
     * <p>
     * The thread represented by this thread is forced to stop whatever
     * it is doing abnormally and to throw a newly created
     * <code>ThreadDeath</code> object as an exception.
     * <p>
     * It is permitted to stop a thread that has not yet been started.
     * If the thread is eventually started, it immediately terminates.
     * <p>
     * An application should not normally try to catch
     * <code>ThreadDeath</code> unless it must do some extraordinary
     * cleanup operation (note that the throwing of
     * <code>ThreadDeath</code> causes <code>finally</code> clauses of
     * <code>try</code> statements to be executed before the thread
     * officially dies).  If a <code>catch</code> clause catches a
     * <code>ThreadDeath</code> object, it is important to rethrow the
     * object so that the thread actually dies.
     * <p>
     * The top-level error handler that reacts to otherwise uncaught
     * exceptions does not print out a message or otherwise notify the
     * application if the uncaught exception is an instance of
     * <code>ThreadDeath</code>.
     *
     * @exception  SecurityException  if the current thread cannot
     *               modify this thread.
     * @see        #interrupt()
     * @see        #checkAccess()
     * @see        #run()
     * @see        #start()
     * @see        ThreadDeath
     * @see        ThreadGroup#uncaughtException(Thread,Throwable)
     * @see        SecurityManager#checkAccess(Thread)
     * @see        SecurityManager#checkPermission
     * @deprecated This method is inherently unsafe.  Stopping a thread with
     *       Thread.stop causes it to unlock all of the monitors that it
     *       has locked (as a natural consequence of the unchecked
     *       <code>ThreadDeath</code> exception propagating up the stack).  If
     *       any of the objects previously protected by these monitors were in
     *       an inconsistent state, the damaged objects become visible to
     *       other threads, potentially resulting in arbitrary behavior.  Many
     *       uses of <code>stop</code> should be replaced by code that simply
     *       modifies some variable to indicate that the target thread should
     *       stop running.  The target thread should check this variable
     *       regularly, and return from its run method in an orderly fashion
     *       if the variable indicates that it is to stop running.  If the
     *       target thread waits for long periods (on a condition variable,
     *       for example), the <code>interrupt</code> method should be used to
     *       interrupt the wait.
     *       For more information, see
     *       <a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">Why
     *       are Thread.stop, Thread.suspend and Thread.resume Deprecated?</a>.
     */
   
    /**
    * 强制线程停止执行(不推荐)
    * 如果安装了安全管理器,它的checkAccess 方法this作为参数。这可能导致 SecurityException 被提升(在当前线程中)
    * 如果此线程与当前线程不同(即当前线程试图停止除本身线程之外的线程) ,则另外还调用安全管理里器的 checkPermission 
    * 方法。在这种情况下,这可能会抛出 SecurityException 异常(在当前线程中)
    * 由该线程表示的线程被强制停止,它正在异常进行,并抛出一个新键的 ThreadDeath 对象作为例外
    * 允许停止尚未启动的线程。如果线程最终启动,它将立即终止
    * 一个应用程序通常不应该尝试捕获 ThreadDeath ,除非它必须做一些非凡的清除工作(注意:抛出ThreadDeath对象导致 
    * finally 语句try语句在线程正式死亡前执行  )。如果一个 catch 子句捕获一个 ThreadDeath 对象,重要的是重新抛出
    * 该对象,使线程实际上死亡
    * 捕获的异常不打印出消息,或者未捕获的异常是一个实例,否则通知应用程序的顶级错误处理程序 ThreadDeath 
    */
    //这个方法本质上是不安全的。使用Thread.stop 停止线程可以解锁所有已锁定的监视器(由ThreadDeath异常在堆栈中的
    //自然结果)。如果先前受这些监视器保护的任何对象处于不一致的状态,则损坏的对象变得对其他线程可见,可能会导致任意
    //行为
    @Deprecated
    public final void stop() {
        SecurityManager security = System.getSecurityManager();
        if (security != null) {
            checkAccess();
            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.
        //状态值 0 对应于 “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());
    }
 /**
     * Interrupts this thread.
     *
     * <p> Unless the current thread is interrupting itself, which is
     * always permitted, the {@link #checkAccess() checkAccess} method
     * of this thread is invoked, which may cause a {@link
     * SecurityException} to be thrown.
     *
     * <p> If this thread is blocked in an invocation of the {@link
     * Object#wait() wait()}, {@link Object#wait(long) wait(long)}, or {@link
     * Object#wait(long, int) wait(long, int)} methods of the {@link Object}
     * class, or of the {@link #join()}, {@link #join(long)}, {@link
     * #join(long, int)}, {@link #sleep(long)}, or {@link #sleep(long, int)},
     * methods of this class, then its interrupt status will be cleared and it
     * will receive an {@link InterruptedException}.
     *
     * <p> If this thread is blocked in an I/O operation upon an {@link
     * java.nio.channels.InterruptibleChannel InterruptibleChannel}
     * then the channel will be closed, the thread's interrupt
     * status will be set, and the thread will receive a {@link
     * java.nio.channels.ClosedByInterruptException}.
     *
     * <p> If this thread is blocked in a {@link java.nio.channels.Selector}
     * then the thread's interrupt status will be set and it will return
     * immediately from the selection operation, possibly with a non-zero
     * value, just as if the selector's {@link
     * java.nio.channels.Selector#wakeup wakeup} method were invoked.
     *
     * <p> If none of the previous conditions hold then this thread's interrupt
     * status will be set. </p>
     *
     * <p> Interrupting a thread that is not alive need not have any effect.
     *
     * @throws  SecurityException
     *          if the current thread cannot modify this thread
     *
     * @revised 6.0
     * @spec JSR-51
     */
     /**
     * 中断这个线程
     * 除非始终允许当前线程中断自身,否则将调用次线程的checkAccess方法,这可能会引发 SecurityException
     * 如果该线程阻塞的调用wait(),wait(long),或 wait(long,int)的方法 或者
     * join(),join(long),join(long,int),sleep(long),或 sleep(long,int)方法,那么它的中断状态将被清
     * 除,并且将收到一个 InterruptedException 
     * 如果该线程在 InterruptibleChannel 上的I/O操作被终止 则通道将被关闭,该线程的中断状态将被设置,并将收
     * 到 ClosedInterruptException
     * 如果该线程在 Selector 中被阻塞,则线程的中断状态将被设置,并且它将从选择操作立即返回,可能具有非零值,就像调
     * 用了选择器 wakeup 方法一样。
     * 如果以前的条件都不成立,则该线程的中断状态将被设置
     * 中断不存在的线程不需要任何效果
     *
     */
    public void interrupt() {
        if (this != Thread.currentThread())
            checkAccess();

        synchronized (blockerLock) {
            Interruptible b = blocker;
            if (b != null) {
                interrupt0();           // Just to set the interrupt flag
                b.interrupt(this);
                return;
            }
        }
        interrupt0();
    }
/**
     * Tests whether the current thread has been interrupted.  The
     * <i>interrupted status</i> of the thread is cleared by this method.  In
     * other words, if this method were to be called twice in succession, the
     * second call would return false (unless the current thread were
     * interrupted again, after the first call had cleared its interrupted
     * status and before the second call had examined it).
     *
     * <p>A thread interruption ignored because a thread was not alive
     * at the time of the interrupt will be reflected by this method
     * returning false.
     *
     * @return  <code>true</code> if the current thread has been interrupted;
     *          <code>false</code> otherwise.
     * @see #isInterrupted()
     * @revised 6.0
     */
     /**
     * 测是当前线程是否中断。线程的中断状态被这个方法清除。换句话说,如果这个方法被成功调用两次,第二次调用将返回
     * false (除非当前线程再一次被中断,在第一次调用后已经被清除它的中断标记,并且在第二次调用前已经检查过)
     */
    public static boolean interrupted() {
        return currentThread().isInterrupted(true);
    }

/**
     * Tests whether this thread has been interrupted.  The <i>interrupted
     * status</i> of the thread is unaffected by this method.
     *
     * <p>A thread interruption ignored because a thread was not alive
     * at the time of the interrupt will be reflected by this method
     * returning false.
     *
     * @return  <code>true</code> if this thread has been interrupted;
     *          <code>false</code> otherwise.
     * @see     #interrupted()
     * @revised 6.0
     */
     /**
     * 测试这个线程是否已经被中断,线程的中断状态不受此方法的影响
     */
    public boolean isInterrupted() {
        return isInterrupted(false);
    }

    /**
     * Tests if some Thread has been interrupted.  The interrupted state
     * is reset or not based on the value of ClearInterrupted that is
     * passed.
     * 根据传递的 ClearInterrupted 的值,是否重置中断状态
     */
    private native boolean isInterrupted(boolean ClearInterrupted);

这一块有丢丢小坑:
在上面的源码中,可以看到以下这两个方法:

//注意这个没有用static修饰的是中断开启的 thread 对象
 public void interrupt()  
// 注意这个有 static 修饰的方法,中断的是调用该线程的线程(我们知道,是存在两个线程的,比如我们在main中开启一个线程执行我们想要
// 的程序,这里存在两个线程,第一个就是我们的主线程,另一个是我们开启的线程 ),这个方法中断的是 调用执行这个方法的线程,也就是
// 说:interrupted() 作用于当前线程
 public static boolean interrupted() 

我不知道有没说清楚,如图:
在这里插入图片描述

//这两个稍微看一下吧,平时感觉也没用到过,返回的数据是一个 StackTraceElement 数组,每一个都代表着一个栈帧(不知道的可以百度或《java虚拟机
//规范》中有提到,记得不是很清楚了),效果如下:
public StackTraceElement[] getStackTrace() 

public static Map<Thread, StackTraceElement[]> getAllStackTraces()

代码:

	@Test
	public void test3() {
		Thread thread = new Thread(()->{
			System.out.println("启动线程名:"+Thread.currentThread().getName());

			while(true) {
				Thread.currentThread().getName();
			}
		});
		thread.start();
		System.out.println("--------------------------------");
		StackTraceElement[] vals = thread.getStackTrace();
		System.out.println("thread "+thread.getName()+" : ");
		for(StackTraceElement val:vals) {
			System.out.println("   ==> "+val);
		}
		System.out.println("--------------------------------");
		Map<Thread,StackTraceElement[]> map = Thread.getAllStackTraces();
		Set<Thread> threads = map.keySet(); 
		for(Thread key:threads) {
			StackTraceElement[] values = map.get(key);
			System.out.println("key:"+key.getName()+ ": ");
			for(StackTraceElement value:values) {
				System.out.println("     "+value);
			}
		}
	}

效果:
在这里插入图片描述
在这里插入图片描述
可以看到运行两次,得到的栈帧是不同的(当然可能也是相同的),所以利用这个方法对问题进行排查时,要注意要使数据加载进栈帧中才能得到完整的数据,不然得到的数据可能不完整,给问题排查造成困难

    /** cache of subclass security audit results */
    /* Replace with ConcurrentReferenceHashMap when/if it appears in a future
     * release */
    // 子类安全审核结果的缓存
    // 当/如果它在将来的版本中出现,请用 ConcurrentReferenceHashMap 替换
    private static class Caches {  //注意: 这是一个类,有时候看着看着就看漏了
        /** cache of subclass security audit results */
        static final ConcurrentMap<WeakClassKey,Boolean> subclassAudits =
            new ConcurrentHashMap<>();

        /** queue for WeakReferences to audited subclasses */
        // 已审计子类弱引用队列
        static final ReferenceQueue<Class<?>> subclassAuditsQueue =
            new ReferenceQueue<>();
    }
    /**
     * Verifies that this (possibly subclass) instance can be constructed
     * without violating security constraints: the subclass must not override
     * security-sensitive non-final methods, or else the
     * "enableContextClassLoaderOverride" RuntimePermission is checked.
     */
    private static boolean isCCLOverridden(Class<?> cl) {
        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();
    }
    /**
     * Verifies that this (possibly subclass) instance can be constructed
     * without violating security constraints: the subclass must not override
     * security-sensitive non-final methods, or else the
     * "enableContextClassLoaderOverride" RuntimePermission is checked.
     */
     // 验证是否可以在不违反安全约束的情况下构造此(可能是子类)实例:子类不得覆盖对安全性敏感的非最终方法,否则将检查 
     // “enableContextClassLoaderOverride” RuntimePermission 
    private static boolean isCCLOverridden(Class<?> cl) {
        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();
    }
/**
     * Performs reflective checks on given subclass to verify that it doesn't
     * override security-sensitive non-final methods.  Returns true if the
     * subclass overrides any of the methods, false otherwise.
     */
     //使用反射的方式去检查验证子类它没有重写安全敏感非最终方法,如果重写了将返回 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;  // 参数类不是 Thread 类
                         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();
    }

  public enum State {   // 线程的状态
        /**
         * Thread state for a thread which has not yet started.
         */
         //线程还未启动时的状态
        NEW,

        /**
         * Thread state for a runnable thread.  A thread in the runnable
         * state is executing in the Java virtual machine but it may
         * be waiting for other resources from the operating system
         * such as processor.
         */
         // 一个可运行的状态,在java虚拟机中,一个线程在可运行状态是正在执行的,但它可能正在等待操作系统的其它资源,
         // 例如:处理器资源
        RUNNABLE,

        /**
         * Thread state for a thread blocked waiting for a monitor lock.
         * A thread in the blocked state is waiting for a monitor lock
         * to enter a synchronized block/method or
         * reenter a synchronized block/method after calling
         * {@link Object#wait() Object.wait}.
         */
         // 线程的阻塞状态是等待一个监视器锁
         // 一个阻塞状态的线程是正在等待监视器锁去进入一个同步块/方法,或者 在调用Object的wait方法后,重新进入一个同步块/方法
        BLOCKED,

        /**
         * Thread state for a waiting thread.
         * A thread is in the waiting state due to calling one of the
         * following methods:
         * <ul>
         *   <li>{@link Object#wait() Object.wait} with no timeout</li>
         *   <li>{@link #join() Thread.join} with no timeout</li>
         *   <li>{@link LockSupport#park() LockSupport.park}</li>
         * </ul>
         *
         * <p>A thread in the waiting state is waiting for another thread to
         * perform a particular action.
         *
         * For example, a thread that has called <tt>Object.wait()</tt>
         * on an object is waiting for another thread to call
         * <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
         * that object. A thread that has called <tt>Thread.join()</tt>
         * is waiting for a specified thread to terminate.
         */
        WAITING,

        /**
         * Thread state for a waiting thread with a specified waiting time.
         * A thread is in the timed waiting state due to calling one of
         * the following methods with a specified positive waiting time:
         * <ul>
         *   <li>{@link #sleep Thread.sleep}</li>
         *   <li>{@link Object#wait(long) Object.wait} with timeout</li>
         *   <li>{@link #join(long) Thread.join} with timeout</li>
         *   <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
         *   <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
         * </ul>
         */
         // 一个等待线程伴随一个特定的等待时间
         // 一个线程在定时等待状态由于调用了以下指定的方法
         // Thread.sleep  Object.wait(long)(注意:这里这个有参数)  Thread.join(long)  
         // LockSupport.parkNanos   LockSupport.parkUnitil 
         //
        TIMED_WAITING,

        /**
         * Thread state for a terminated thread.
         * The thread has completed execution.
         */
         // 线程终止状态
         // 线程已经完成执行
        TERMINATED;
    }

 /**
     * Interface for handlers invoked when a <tt>Thread</tt> abruptly
     * terminates due to an uncaught exception.
     * <p>When a thread is about to terminate due to an uncaught exception
     * the Java Virtual Machine will query the thread for its
     * <tt>UncaughtExceptionHandler</tt> using
     * {@link #getUncaughtExceptionHandler} and will invoke the handler's
     * <tt>uncaughtException</tt> method, passing the thread and the
     * exception as arguments.
     * If a thread has not had its <tt>UncaughtExceptionHandler</tt>
     * explicitly set, then its <tt>ThreadGroup</tt> object acts as its
     * <tt>UncaughtExceptionHandler</tt>. If the <tt>ThreadGroup</tt> object
     * has no
     * special requirements for dealing with the exception, it can forward
     * the invocation to the {@linkplain #getDefaultUncaughtExceptionHandler
     * default uncaught exception handler}.
     *
     * @see #setDefaultUncaughtExceptionHandler
     * @see #setUncaughtExceptionHandler
     * @see ThreadGroup#uncaughtException
     * @since 1.5
     */
     /**
     * 这个方法比较重要
     * 当一个 uncaught exception 导致线程突然终止时,调用这个接口的处理方法
     * 当由于未捕获异常导致一个线程即将终止时,Java虚拟机将会通过getUncaughtExceptionHandler方法查询这个线程的未捕获异常处理器
     * (UncaughtExceptionHandler),并且将会调用这个处理器的 uncaughtException 方法,将线程和异常作为参数传递
     * 如果没有显示设置线程的 UncaughtExceptionHandler,则其 ThreadGroup 对象将用作其 UncaughtExceptionHandler。
     * 如果线程组(ThreadGroup)对象也没有指定要求去处理这个异常, 它将调用转发到默认的未捕获异常处理程序
     * (getDefaultUncaughtExceptionHandler) 中
     */
    @FunctionalInterface   //声明这是一个函数式接口
    public interface UncaughtExceptionHandler {
        /**
         * Method invoked when the given thread terminates due to the
         * given uncaught exception.
         * <p>Any exception thrown by this method will be ignored by the
         * Java Virtual Machine. 
         * @param t the thread
         * @param e the exception
         */
         /**
         * 由于的未捕获异常(uncaught exception)导致线程终止时,方法被调用
         * Java 虚拟机将忽略此方法引发的任何异常(也就是说,这个方法产生的异常不能在往外抛了,抛了虚拟机也会忽略不进行处理)
         * 它的set和get 方法就没必要说了,但要注意默认的前面有 static 修饰
         */
        void uncaughtException(Thread t, Throwable e);
    }
	// The following three initially uninitialized fields are exclusively
    // managed by class java.util.concurrent.ThreadLocalRandom. These
    // fields are used to build the high-performance PRNGs in the
    // concurrent code, and we can not risk accidental false sharing.
    // Hence, the fields are isolated with @Contended.

    // 以下三个最初未初始化的字段仅由类 java.util.concurrent.ThreadLocalRandom 管理
    // 这些字段用于在并发代码中购机按搞性能 PRNG,因此我们不会冒意外的错误共享的风险
    // 因此,使用 @Contended. 隔离字段
    // 意外发现新大陆了!!!结尾有惊喜
    
    /** The current seed for a ThreadLocalRandom */
    // ThreadLocalRandom的当前种子
    @sun.misc.Contended("tlr")
    long threadLocalRandomSeed;

    /** Probe hash value; nonzero if threadLocalRandomSeed initialized */
    // 探针哈希值;如果 threadLocalRandomSeed 初始化,则为非零
    @sun.misc.Contended("tlr")
    int threadLocalRandomProbe;

    /** Secondary seed isolated from public ThreadLocalRandom sequence */
    // 从公共 ThreadLocalRandom 序列中分离的次要种子  这些是什么我暂时也不知道,先放这里一段时间吧!!!
    @sun.misc.Contended("tlr")
    int threadLocalRandomSecondarySeed;
  • 10
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值