多线程——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)中的构造函数或方法将引发空指针异常

Ⅱ、类结构说明

多线程——Thread(包括sleep是否会占用CPU资源验证)_第1张图片

Ⅲ、属性声明

    /* Make sure registerNatives is the first thing  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.
     *
     * 

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. * *

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
     *          interrupted status 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 使用情况并不高,程序中的线程确实是存在的
多线程——Thread(包括sleep是否会占用CPU资源验证)_第2张图片
② 创建和第一次实验一样多的线程,只使其中一半线程 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%,
多线程——Thread(包括sleep是否会占用CPU资源验证)_第3张图片
问题分析:

第一次 第二次
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-"+}n, where n 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-"+}n, where n 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 run method of this thread.
     * 

* The result is that two threads are running concurrently: the * current thread (which returns from the call to the * start method) and the other thread (which executes its * run method). *

* 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
     * Runnable run object, then that
     * Runnable object's run method is called;
     * otherwise, this method does nothing and returns.
     * 

* Subclasses of Thread 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.
     * 

* If there is a security manager installed, its checkAccess * method is called with this * as its argument. This may result in a * SecurityException being raised (in the current thread). *

* 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 checkPermission method (with a * RuntimePermission("stopThread") argument) is called in * addition. * Again, this may result in throwing a * SecurityException (in the current thread). *

* The thread represented by this thread is forced to stop whatever * it is doing abnormally and to throw a newly created * ThreadDeath object as an exception. *

* It is permitted to stop a thread that has not yet been started. * If the thread is eventually started, it immediately terminates. *

* An application should not normally try to catch * ThreadDeath unless it must do some extraordinary * cleanup operation (note that the throwing of * ThreadDeath causes finally clauses of * try statements to be executed before the thread * officially dies). If a catch clause catches a * ThreadDeath object, it is important to rethrow the * object so that the thread actually dies. *

* 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 * ThreadDeath. * * @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 * ThreadDeath 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 stop 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 interrupt method should be used to * interrupt the wait. * For more information, see * Why * are Thread.stop, Thread.suspend and Thread.resume Deprecated?. */ /** * 强制线程停止执行(不推荐) * 如果安装了安全管理器,它的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.
     *
     * 

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. * *

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}. * *

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}. * *

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. * *

If none of the previous conditions hold then this thread's interrupt * status will be set.

* *

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
     * interrupted status 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).
     *
     * 

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 true if the current thread has been interrupted; * false otherwise. * @see #isInterrupted() * @revised 6.0 */ /** * 测是当前线程是否中断。线程的中断状态被这个方法清除。换句话说,如果这个方法被成功调用两次,第二次调用将返回 * false (除非当前线程再一次被中断,在第一次调用后已经被清除它的中断标记,并且在第二次调用前已经检查过) */ public static boolean interrupted() { return currentThread().isInterrupted(true); }

/**
     * Tests whether this thread has been interrupted.  The interrupted
     * status of the thread is unaffected by this method.
     *
     * 

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 true if this thread has been interrupted; * false 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() 

我不知道有没说清楚,如图:
多线程——Thread(包括sleep是否会占用CPU资源验证)_第4张图片

//这两个稍微看一下吧,平时感觉也没用到过,返回的数据是一个 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);
			}
		}
	}

效果:
多线程——Thread(包括sleep是否会占用CPU资源验证)_第5张图片
多线程——Thread(包括sleep是否会占用CPU资源验证)_第6张图片
可以看到运行两次,得到的栈帧是不同的(当然可能也是相同的),所以利用这个方法对问题进行排查时,要注意要使数据加载进栈帧中才能得到完整的数据,不然得到的数据可能不完整,给问题排查造成困难

    /** 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:
         * 
    *
  • {@link Object#wait() Object.wait} with no timeout
  • *
  • {@link #join() Thread.join} with no timeout
  • *
  • {@link LockSupport#park() LockSupport.park}
  • *
* *

A thread in the waiting state is waiting for another thread to * perform a particular action. * * For example, a thread that has called Object.wait() * on an object is waiting for another thread to call * Object.notify() or Object.notifyAll() on * that object. A thread that has called Thread.join() * 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: *

    *
  • {@link #sleep Thread.sleep}
  • *
  • {@link Object#wait(long) Object.wait} with timeout
  • *
  • {@link #join(long) Thread.join} with timeout
  • *
  • {@link LockSupport#parkNanos LockSupport.parkNanos}
  • *
  • {@link LockSupport#parkUntil LockSupport.parkUntil}
  • *
*/
// 一个等待线程伴随一个特定的等待时间 // 一个线程在定时等待状态由于调用了以下指定的方法 // 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 Thread abruptly
     * terminates due to an uncaught exception.
     * 

When a thread is about to terminate due to an uncaught exception * the Java Virtual Machine will query the thread for its * UncaughtExceptionHandler using * {@link #getUncaughtExceptionHandler} and will invoke the handler's * uncaughtException method, passing the thread and the * exception as arguments. * If a thread has not had its UncaughtExceptionHandler * explicitly set, then its ThreadGroup object acts as its * UncaughtExceptionHandler. If the ThreadGroup 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. *

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;

你可能感兴趣的:(Java基础学习,java,多线程)