【Java原理系列】 Java中Thread原理用法示例源码详解

Java中Thread原理用法示例源码详解

原理

在Java中,Thread(线程)是实现并发执行的基本单位。每个线程都有自己的执行路径和执行状态,并且可以独立地执行代码。

Java中的线程原理主要涉及以下几个方面:

  1. 线程调度:Java线程是由操作系统的线程调度器进行管理和调度的。操作系统为每个Java线程分配一定的CPU时间片,使得多个线程可以交替执行。线程调度器根据调度算法决定当前应该执行哪个线程,以及何时切换到另一个线程。

  2. 线程状态:Java线程具有不同的状态,包括新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)和终止(Terminated)。线程可以通过调用start()方法启动,进入就绪状态等待被调度执行。当线程获得CPU时间片后,进入运行状态执行任务。当线程需要等待某些条件满足时,如等待I/O操作完成,它会进入阻塞状态。当线程执行完毕或者异常终止时,进入终止状态。

  3. 线程同步:多个线程同时访问共享数据时,可能引发数据不一致性或竞态条件。Java提供了多种机制来实现线程间的同步,例如使用synchronized关键字实现互斥访问共享资源,使用wait()notify()方法实现线程间的等待和通知机制,以及使用LockCondition接口提供更灵活的同步控制。

  4. 线程间通信:线程之间需要进行数据交换和协调。Java提供了多种方式来实现线程间的通信,例如使用共享内存、管道、队列等数据结构,在多个线程之间传递数据。此外,Java还提供了一些高级的并发工具类,如CountDownLatchCyclicBarrierSemaphore,用于更复杂的线程间协作。

  5. 线程生命周期管理:Java中的线程可以通过继承Thread类或实现Runnable接口来创建。线程的生命周期包括创建、运行、阻塞和终止等阶段。可以通过调用线程的start()方法启动线程,并使用join()方法等待线程执行完成。此外,还可以使用interrupt()方法中断线程的执行。

总之,Java的线程原理涉及线程调度、线程状态管理、线程同步和线程间通信等方面,通过操作系统的线程调度器实现并发执行,通过各种同步机制和通信机制来保证线程安全和协作。

用法

以下是Thread类最常用的一些方法:

  • public synchronized void start(): 启动线程,使其进入可执行状态。
  • public final void join() throws InterruptedException: 等待该线程执行完成。
  • public void run(): 定义线程的任务逻辑,线程启动后会执行此方法中的代码。
  • public void interrupt(): 中断线程。
  • public boolean isInterrupted(): 检查线程是否被中断。

这些方法是Thread类中最常用和重要的方法。start()方法用于启动线程,join()方法用于等待线程执行完成。run()方法定义了线程的具体任务逻辑,interrupt()方法用于中断线程,isInterrupted()方法用于检查线程的中断状态。

其他方法包括获取线程的ID、名称、优先级等信息的方法,以及设置线程的上下文类加载器、异常处理器等辅助功能。

请注意,虽然Thread类提供了许多其他方法,但上述列出的方法是在实际多线程编程中最常用和核心的方法。

示例

以下是对Thread类中最常用的方法进行详解介绍、适用场景和代码示例:

  1. public synchronized void start()
    • 作用:启动线程,使其进入可执行状态。
    • 适用场景:当需要在程序中创建新的线程并开始执行时,使用start()方法来启动线程。
    • 示例代码:
Thread thread = new MyThread();
thread.start();
  1. public final void join() throws InterruptedException
    • 作用:等待该线程执行完成。
    • 适用场景:当需要等待某个线程执行完毕后再继续执行其他操作时,可以使用join()方法来等待线程执行完成。
    • 示例代码:
Thread thread = new MyThread();
thread.start();

try {
    thread.join();
} catch (InterruptedException e) {
    e.printStackTrace();
}
  1. public void run()
    • 作用:定义线程的任务逻辑,线程启动后会执行此方法中的代码。
    • 适用场景:在自定义的线程类中,重写run()方法来实现具体的线程任务逻辑。
    • 示例代码:
class MyThread extends Thread {
    public void run() {
        // 线程任务逻辑
    }
}
  1. public void interrupt()
    • 作用:中断线程。
    • 适用场景:当需要中断正在执行的线程时,可以调用interrupt()方法来请求中断线程。
    • 示例代码:
Thread thread = new MyThread();
thread.start();

// 中断线程
thread.interrupt();
  1. public boolean isInterrupted()
    • 作用:检查线程是否被中断。
    • 适用场景:当需要在线程中检查自身是否被中断,并根据中断状态进行相应的处理时,可以使用isInterrupted()方法。
    • 示例代码:
public void run() {
    while (!isInterrupted()) {
        // 线程任务逻辑
    }
}

这些方法是Thread类中最常用和重要的方法。start()方法用于启动线程,join()方法用于等待线程执行完成。run()方法定义了线程的具体任务逻辑,interrupt()方法用于中断线程,isInterrupted()方法用于检查线程的中断状态。

请注意,每个方法都有不同的使用场景和目的,根据具体需求选择合适的方法来管理和控制线程的行为。

经典示例

1.线程创建

class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("Thread 1 is running");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Thread 1 has finished");
    }
}

class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("Thread 2 is running");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("Thread 2 has finished");
    }
}

public class Main {
    public static void main(String[] args) {
        MyThread thread1 = new MyThread();
        thread1.start();

        MyRunnable runnable = new MyRunnable();
        Thread thread2 = new Thread(runnable);
        thread2.start();
        
        System.out.println("Main thread continues to run");
    }
}

这个示例创建了两个线程:一个是通过继承Thread类创建的线程(MyThread),另一个是通过实现Runnable接口创建的线程(MyRunnable)。在每个线程的run()方法中,打印一条消息并休眠1秒钟来模拟执行任务。在主线程中,也打印一条消息。

输出结果应该类似于以下内容:

Thread 1 is running
Thread 2 is running
Main thread continues to run
Thread 2 has finished
Thread 1 has finished

注意,由于线程调度的不确定性,线程的执行顺序可能会有所不同。但是,无论执行顺序如何,主线程都会继续运行,并且两个子线程都会执行完毕后结束。

2.线程安全停止

可以使用一个boolean类型的标志位来控制线程的运行状态,在外部通过设置标志位来通知线程停止。

package org.example;

/**
 * @program: sparkPomProject
 * @description: 安全停止线程
 * @author: Mr.Lee
 * @create: 2023-10-14 20:40
 **/

public class ThreadSafeStopTest {
    public static void main(String[] args) {
        MyThread1 thread = new MyThread1();
        thread.start();

        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 停止线程
        thread.stopRunning();
    }
}

class MyThread1 extends Thread {
    private volatile boolean running = true;

    public void stopRunning() {
        running = false;
    }

    @Override
    public void run() {
        while (running) {
            try {
                Thread.sleep(1000);
                System.out.println("I am working now");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
//
//I am working now
//I am working now
//I am working now

3.线程中断处理

当一个线程处于阻塞状态(如调用了sleep()或wait()方法)时,可以通过调用interrupt()方法来中断线程。在线程的run()方法中,可以使用isInterrupted()方法检查线程是否被中断,并做相应的处理。

package org.example;

/**
 * @program: sparkPomProject
 * @description: 线程中断测试
 * @author: Mr.Lee
 * @create: 2023-10-14 20:46
 **/

public class ThreadInteruptTest {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            while (!Thread.currentThread().isInterrupted()) {
                try {
                    // 模拟线程执行任务
                    System.out.println("Thread is running...");
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    // 捕获中断异常并处理
                    System.out.println("Thread is interrupted");
                    Thread.currentThread().interrupt(); // 重新设置中断状态
                }
            }
        });

        thread.start();

        // 让主线程休眠一段时间后,中断子线程
        Thread.sleep(5000);
        thread.interrupt();

        thread.join();
        System.out.println("Main thread exits");
    }
}
//Thread is running...
//Thread is running...
//Thread is running...
//Thread is running...
//Thread is running...
//Thread is interrupted
//Main thread exits

4.线程组

使用线程组(ThreadGroup)来进行线程管理和监控。通过将线程归类到特定的线程组中,我们可以方便地对线程组内的线程进行批量操作,例如启动、停止或监视等。

package org.example;

/**
 * @program: sparkPomProject
 * @description: 线程组测试
 * @author: Mr.Lee
 * @create: 2023-10-14 20:53
 **/

public class ThreadGroupTest {
    public static void main(String[] args) throws InterruptedException {
        ThreadGroup threadGroup = new ThreadGroup("MyThreadGroup");

        Thread thread1 = new Thread(threadGroup, () -> {
            System.out.println("Thread 1 is running");
        });

        Thread thread2 = new Thread(threadGroup, () -> {
            System.out.println("Thread 2 is running");
        });

        thread1.start();
        thread2.start();

        // 输出线程组信息
        threadGroup.list();

        // 等待线程组中的所有线程执行完成
        while (threadGroup.activeCount() > 0) {
            Thread.sleep(100);
        }

        System.out.println("All threads in the thread group have finished");
    }
}
//java.lang.ThreadGroup[name=MyThreadGroup,maxpri=10]
//Thread[Thread-0,5,MyThreadGroup]
//Thread[Thread-1,5,MyThreadGroup]
//Thread 2 is running
//Thread 1 is running
//All threads in the thread group have finished

5.线程间通信

package org.example;

/**
 * @program: sparkPomProject
 * @description: 线程间通信
 * @author: Mr.Lee
 * @create: 2023-10-14 12:43
 **/

public class ThreadCommunicateTest {
    public static void main(String[] args) {
        Message message = new Message();

        Thread producerThread = new Thread(() -> {
            for (int i = 1; i <= 5; i++) {
                String msg = "Message " + i;
                message.produce(msg);
                System.out.println("Producer produced: " + msg);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        Thread consumerThread = new Thread(() -> {
            for (int i = 1; i <= 5; i++) {
                String msg = message.consume();
                System.out.println("Consumer consumed: " + msg);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        producerThread.start();
        consumerThread.start();

        try {
            producerThread.join();
            consumerThread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
class Message {
    private String content;
    private boolean isProduced = false;

    public synchronized void produce(String message) {
        while (isProduced) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        this.content = message;
        isProduced = true;
        notifyAll();
    }

    public synchronized String consume() {
        while (!isProduced) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        isProduced = false;
        notifyAll();
        return content;
    }
}

6.线程同步

public class ThreadTest {
    static class SharedData {
        private int count;

        // Getter and setter methods
        public synchronized void setCount(int count) {
            this.count = count;
        }

        public synchronized int getCount() {
            return count;
        }
    }

    public static void main(String[] args) throws InterruptedException {
        SharedData sharedData = new SharedData();

        Thread thread1 = new Thread(() -> {
            sharedData.setCount(sharedData.getCount() + 1);
        });

        Thread thread2 = new Thread(() -> {
            sharedData.setCount(sharedData.getCount() + 1);
        });

        thread1.start();
        thread2.start();

        thread1.join();
        thread2.join();

        System.out.println("Final count: " + sharedData.getCount());
    }
}

在这个示例中,我们创建了一个SharedData类,它有一个私有的count变量,并提供了setCount()和getCount()方法来设置和获取计数器的值。为了确保线程安全,我们使用synchronized关键字修饰这两个方法,以实现互斥访问共享资源。

在主线程中,我们创建了两个线程(thread1和thread2),它们共享同一个SharedData对象。每个线程都会对count进行加一操作。最后,我们等待这两个线程执行完成,并输出计数器的最终值。

由于使用了同步机制,多个线程在访问共享数据时会进行互斥操作,从而避免了数据竞争和不一致性。输出结果应该是2,表示两个线程分别对计数器进行了加一操作。

7.线程局部变量:

使用ThreadLocal类可以为每个线程创建一个独立的变量副本,使得每个线程都拥有自己的变量副本,避免了线程间的数据竞争。

package org.example;

/**
 * @program: sparkPomProject
 * @description: 线性局部变量
 * @author: Mr.Lee
 * @create: 2023-10-14 20:35
 **/
class MyThread implements Runnable {
    private static ThreadLocal<Integer> threadLocal = new ThreadLocal<>();

    @Override
    public void run() {
        threadLocal.set(10);
        System.out.println("Thread " + Thread.currentThread().getId() + ": " + threadLocal.get());
    }
}

public class LocalThreadTest {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        Thread thread1 = new Thread(myThread);
        Thread thread2 = new Thread(myThread);
        thread1.start();
        thread2.start();
    }
}
//Thread 21: 10
//Thread 20: 10

中文源码

/**
 * 线程是程序中的执行线程。Java虚拟机允许应用程序同时运行多个线程。
 *
 * 每个线程都有一个优先级。优先级较高的线程会优先执行。每个线程可能被标记为守护线程。当某个线程创建一个新的Thread对象时,新线程的优先级初始值与创建线程的优先级相同,如果创建线程是守护线程,则新线程也是守护线程。
 *
 * 当Java虚拟机启动时,通常会有一个非守护线程(通常是调用某个指定类的main方法)。Java虚拟机会继续执行线程,直到发生以下情况之一:
 * - 调用Runtime类的exit方法并且安全管理器允许退出操作。
 * - 所有非守护线程都已结束,要么通过从run方法返回,要么通过抛出超出run方法范围的异常。
 *
 * 创建新线程有两种方式。一种是声明一个类作为Thread的子类,该子类需要重写Thread类的run方法。然后可以分配并启动该子类的实例。例如,可以编写一个计算大于给定值的素数的线程如下所示:
 *
 * ```java
 * class PrimeThread extends Thread {
 *     long minPrime;
 *     PrimeThread(long minPrime) {
 *         this.minPrime = minPrime;
 *     }
 *
 *     public void run() {
 *         // 计算大于minPrime的素数
 *         ...
 *     }
 * }
 * ```
 *
 * 然后,以下代码将创建一个线程并开始运行它:
 *
 * ```java
 * PrimeThread p = new PrimeThread(143);
 * p.start();
 * ```
 *
 * 另一种创建线程的方式是声明一个实现Runnable接口的类。该类需要实现run方法。然后可以分配该类的实例,并在创建Thread时将其作为参数传递并启动。在另一种样式中,相同的示例如下所示:
 *
 * ```java
 * class PrimeRun implements Runnable {
 *     long minPrime;
 *     PrimeRun(long minPrime) {
 *         this.minPrime = minPrime;
 *     }
 *
 *     public void run() {
 *         // 计算大于minPrime的素数
 *         ...
 *     }
 * }
 * ```
 *
 * 然后,以下代码将创建一个线程并开始运行它:
 *
 * ```java
 * PrimeRun p = new PrimeRun(143);
 * new Thread(p).start();
 * ```
 *
 * 每个线程都有一个用于标识目的的名称。多个线程可能具有相同的名称。如果在线程创建时未指定名称,则会为其生成一个新名称。
 *
 * 除非另有说明,否则将null参数传递给此类中的构造方法或方法将导致抛出NullPointerException异常。
 *
 * @see Runnable
 * @see Runtime#exit(int)
 * @see #run()
 * @see #stop()
 * @since JDK1.0
 */
public class Thread implements Runnable {
    /* 确保registerNatives是<clinit>执行的第一件事情。 */
    private static native void registerNatives();
    static {
        registerNatives();
    }

    private volatile String name;
    private int priority;
    private Thread threadQ;
    private long eetop;

    /* 是否单步执行此线程。 */
    private boolean single_step;

    /* 线程是否为守护线程。 */
    private boolean daemon = false;

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

    /* 将要运行的目标。 */
    private Runnable target;

    /* 该线程所属的线程组 */
    private ThreadGroup group;

    /* 此线程的上下文ClassLoader */
    private ClassLoader contextClassLoader;

    /* 此线程继承的AccessControlContext */
    private AccessControlContext inheritedAccessControlContext;

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

    /* 与此线程相关的ThreadLocal值。此映射由ThreadLocal类维护。 */
    ThreadLocal.ThreadLocalMap threadLocals = null;

    /*
     * 与此线程相关的InheritableThreadLocal值。此映射由InheritableThreadLocal类维护。
     */
    ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;

    /*
     * 此线程的请求堆栈大小,如果创建者未指定堆栈大小,则为0。虚拟机可以使用此数字做任何它想做的事情;某些虚拟机将忽略它。
     */
    private long stackSize;

    /*
     * 原生线程终止后持久存在的JVM私有状态。
     */
    private long nativeParkEventPointer;

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

    /* 生成线程ID */
    private static long threadSeqNumber;

    /* Java线程工具的线程状态,初始化表示线程“尚未启动”。 */
    private volatile int threadStatus = 0;


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

    /**
     * 当前正在执行的线程对象的引用。
     *
     * @return 当前正在执行的线程。
     */
    public static native Thread currentThread();

    /**
     * 提示调度器,当前线程愿意放弃其当前使用处理器的机会。调度器可以忽略此提示。
     *
     * yield是一种启发式尝试,旨在改善本应过度利用CPU的线程之间的相对进展。应与详细的分析和基准测试结合使用,以确保其产生预期效果。
     *
     * 很少适合使用此方法。它可能对调试或测试目的有用,其中它可能有助于重现由竞争条件引起的错误。在设计
     * java.util.concurrent.locks包中的并发控制构造时,它也可能很有用。
     */
    public static native void yield();

    /**
     * 使当前正在执行的线程休眠(暂时停止执行)指定的毫秒数,取决于系统计时器和调度器的精度和准确性。线程不会失去任何监视器的所有权。
     *
     * @param millis 睡眠时间的长度(以毫秒为单位)
     *
     * @throws IllegalArgumentException 如果millis的值为负
     *
     * @throws InterruptedException 如果任何线程中断了当前线程。当抛出此异常时,当前线程的“中断状态”将被清除。
     */
    public static native void sleep(long millis) throws InterruptedException;

    /**
     * 使当前正在执行的线程休眠(暂时停止执行)指定的毫秒数加上指定的纳秒数,取决于系统计时器和调度器的精度和准确性。线程不会失去任何监视器的所有权。
     *
     * @param millis 睡眠时间的长度(以毫秒为单位)
     * @param nanos 附加的纳秒级别睡眠时间(0-999999之间)
     *
     * @throws IllegalArgumentException 如果millis的值为负,或者nanos的值不在范围0-999999内
     *
     * @throws InterruptedException 如果任何线程中断了当前线程。当抛出此异常时,当前线程的“中断状态”将被清除。
     */
    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);
    }

    /**
     * 使用当前AccessControlContext初始化线程。
     *
     * @see #init(ThreadGroup,Runnable,String,long,AccessControlContext,boolean)
     */
    private void init(ThreadGroup g, Runnable target, String name, long stackSize) {
        init(g, target, name, stackSize, null, true);
    }
}

/**
 * 初始化线程。
 *
 * @param g 线程所属的线程组
 * @param target 要调用其run()方法的对象
 * @param name 新线程的名称
 * @param stackSize 新线程的期望堆栈大小,如果为零表示忽略此参数
 * @param acc 继承的AccessControlContext,如果为null则使用AccessController.getContext()
 * @param inheritThreadLocals 如果为true,则从构造线程中继承可继承的线程本地变量的初始值
 */
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) {
        /* 确定是否为Applet */
        /* 如果有安全管理器,则询问安全管理器该如何处理。 */
        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();
    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);
    /* 将指定的堆栈大小存储起来,以备虚拟机使用 */
    this.stackSize = stackSize;

    /* 设置线程ID */
    tid = nextThreadID();
}

/**
 * 抛出CloneNotSupportedException异常,因为无法对Thread进行有意义的克隆。请改用构造一个新的Thread对象。
 *
 * @throws CloneNotSupportedException
 *         总是抛出此异常
 */
@Override
protected Object clone() throws CloneNotSupportedException {
    throw new CloneNotSupportedException();
}

/**
 * 分配一个新的Thread对象。该构造函数的效果与Thread(null, null, gname)相同,其中gname是新生成的名称。自动生成的名称的形式为"Thread-"+n,其中n是一个整数。
 */
public Thread() {
    init(null, null, "Thread-" + nextThreadNum(), 0);
}

/**
 * 分配一个新的Thread对象。该构造函数的效果与Thread(null, target, gname)相同,其中gname是新生成的名称。自动生成的名称的形式为"Thread-"+n,其中n是一个整数。
 *
 * @param target 当线程启动时要调用其run方法的对象。如果为null,则此类的run方法不执行任何操作。
 */
public Thread(Runnable target) {
    init(null, target, "Thread-" + nextThreadNum(), 0);
}

/**
 * 创建一个新的Thread,继承给定的AccessControlContext。这不是一个公共构造函数。
 */
Thread(Runnable target, AccessControlContext acc) {
    init(null, target, "Thread-" + nextThreadNum(), 0, acc, false);
}

/**
 * 分配一个新的Thread对象。该构造函数的效果与Thread(group, target, gname)相同,其中gname是新生成的名称。自动生成的名称的形式为"Thread-"+n,其中n是一个整数。
 *
 * @param group 线程所属的线程组。如果为null并且有安全管理器,则使用SecurityManager.getThreadGroup()确定线程组。如果没有安全管理器或SecurityManager.getThreadGroup()返回null,则线程组设置为当前线程的线程组。
 * @param target 当线程启动时要调用其run方法的对象。如果为null,则此线程的run方法被调用。
 *
 * @throws SecurityException 如果当前线程无法在指定的线程组中创建线程
 */
public Thread(ThreadGroup group, Runnable target) {
    init(group, target, "Thread-" + nextThreadNum(), 0);
}

/**
 * 分配一个新的Thread对象。该构造函数的效果与Thread(null, null, name)相同。
 *
 * @param name 新线程的名称
 */
public Thread(String name) {
    init(null, null, name, 0);
}

/**
 * 分配一个新的Thread对象。该构造函数的效果与Thread(group, null, name)相同。
 *
 * @param group 线程所属的线程组。如果为null并且有安全管理器,则使用SecurityManager.getThreadGroup()确定线程组。如果没有安全管理器或SecurityManager.getThreadGroup()返回null,则线程组设置为当前线程的线程组。
 * @param name 新线程的名称
 *
 * @throws SecurityException 如果当前线程无法在指定的线程组中创建线程
 */
public Thread(ThreadGroup group, String name) {
    init(group, null, name, 0);
}

/**
 * 分配一个新的Thread对象。该构造函数的效果与Thread(null, target, name)相同。
 *
 * @param target 当线程启动时要调用其run方法的对象。如果为null,则此线程的run方法被调用。
 * @param name 新线程的名称
 */
public Thread(Runnable target, String name) {
    init(null, target, name, 0);
}

/**
 * 分配一个新的Thread对象,使其具有target作为其运行对象,将指定的name作为其名称,并属于由group引用的线程组。
 *
 * 如果存在安全管理器,则会调用其checkAccess方法,其中线程组是其参数。
 *
 * 此外,如果直接或间接地由覆盖getContextClassLoader或setContextClassLoader方法的子类的构造函数调用,则会调用其checkPermission方法,并使用RuntimePermission("enableContextClassLoaderOverride")权限。
 *
 * 新创建线程的优先级设置为与创建它的线程相同,即当前运行的线程。可以使用setPriority方法将优先级更改为新值。
 *
 * 新创建的线程最初被标记为守护线程,当且仅当创建它的线程当前被标记为守护线程时。可以使用setDaemon方法更改线程是否为守护线程。
 *
 * @param group 线程所属的线程组。如果为null并且有安全管理器,则使用SecurityManager.getThreadGroup()确定线程组。如果没有安全管理器或SecurityManager.getThreadGroup()返回null,则线程组设置为当前线程的线程组。
 * @param target 当线程启动时要调用其run方法的对象。如果为null,则此线程的run方法被调用。
 * @param name 新线程的名称
 *
 * @throws SecurityException 如果当前线程无法在指定的线程组中创建线程或无法覆盖上下文类加载器方法
 */
public Thread(ThreadGroup group, Runnable target, String name) {
    init(group, target, name, 0);
}

/**
 * 分配一个新的Thread对象,使其具有target作为其运行对象,将指定的name作为其名称,属于由group引用的线程组,并具有指定的堆栈大小。
 *
 * 此构造函数与{@link #Thread(ThreadGroup,Runnable,String)}相同,唯一的区别是它允许指定线程的堆栈大小。堆栈大小是虚拟机为该线程的堆栈分配的近似字节数。<b>如果stackSize参数存在,则其效果高度依赖于平台。</b>
 *
 * 在某些平台上,为stackSize参数指定较高的值可能允许线程在抛出StackOverflowError之前达到更大的递归深度。类似地,为其指定较低的值可能允许更多的线程同时存在而不会抛出OutOfMemoryError(或其他内部错误)。堆栈大小参数的值与最大递归深度和并发级别之间的关系的详细信息是平台相关的。<b>在某些平台上,stackSize参数的值可能根本没有任何影响。</b>
 *
 * 虚拟机可以将stackSize参数视为建议。如果指定的值对于平台来说过小,则虚拟机可能会使用某些特定于平台的最小值;如果指定的值过大,则虚拟机可能会使用某些特定于平台的最大值。同样,虚拟机可以根据需要将指定的值四舍五入(或完全忽略)。
 *
 * 如果stackSize参数的值为零,则此构造函数的行为与{@code Thread(ThreadGroup, Runnable, String)}构造函数完全相同。
 *
 * <i>由于该构造函数的行为与平台相关,因此在使用时必须非常小心。<br>
 * 在不同的JRE实现中,执行给定计算所需的线程堆栈大小可能会有所不同。<br>
 * 鉴于这种差异,可能需要仔细调整堆栈大小参数,并且可能需要为应用程序要运行的每个JRE实现重复调整。</i>
 *
 * 实现注意事项:鼓励Java平台实现者以文档形式记录其实现与stackSize参数的行为。
 *
 * @param group 线程所属的线程组。如果为null并且有安全管理器,则使用SecurityManager.getThreadGroup()确定线程组。如果没有安全管理器或SecurityManager.getThreadGroup()返回null,则线程组设置为当前线程的线程组。
 * @param target 当线程启动时要调用其run方法的对象。如果为null,则此线程的run方法被调用。
 * @param name 新线程的名称
 * @param stackSize 新线程的期望堆栈大小,或者为零以表示忽略此参数。
 *
 * @throws SecurityException 如果当前线程无法在指定的线程组中创建线程
 *
 * @since 1.4
 */
public Thread(ThreadGroup group, Runnable target, String name,
              long stackSize) {
    init(group, target, name, stackSize);
}

/**
 * 导致此线程开始执行;Java虚拟机调用此线程的run方法。
 *
 * 结果是两个线程同时运行:当前线程(从调用start方法返回)和另一个线程(执行其run方法)。
 *
 * 多次启动线程是不合法的。特别地,一旦线程完成执行,就不能重新启动它。
 *
 * @exception  IllegalThreadStateException  如果线程已经启动过。
 * @see        #run()
 * @see        #stop()
 */
public synchronized void start() {
    /**
     * 此方法不适用于主方法线程或VM创建/设置的“system”组线程。将来对此方法添加的任何新功能可能也必须添加到VM中。
     *
     * 零状态值对应于状态"NEW"。
     */
    if (threadStatus != 0)
        throw new IllegalThreadStateException();

    /* 通知线程组,该线程即将启动,
     * 以便将其添加到线程组的线程列表中,
     * 并将线程组的未启动计数减少。 */
    group.add(this);

    boolean started = false;
    try {
        start0();
        started = true;
    } finally {
        try {
            if (!started) {
                group.threadStartFailed(this);
            }
        } catch (Throwable ignore) {
            /* 无操作。如果start0抛出了Throwable,
               它将通过调用堆栈传递上去 */
        }
    }
}

private native void start0();

/**
 * 如果此线程使用单独的Runnable运行对象构造,则调用该Runnable对象的run方法;否则,此方法不执行任何操作并返回。
 *
 * @see     #start()
 * @see     #stop()
 * @see     #Thread(ThreadGroup, Runnable, String)
 */
@Override
public void run() {
    if (target != null) {
        target.run();
    }
}

/**
 * 系统调用此方法以使线程有机会在实际退出之前清理。
 */
private void exit() {
    if (group != null) {
        group.threadTerminated(this);
        group = null;
    }
    /* 强制将所有引用字段置为null:参见bug 4006245 */
    target = null;
    /* 加速释放一些资源 */
    threadLocals = null;
    inheritableThreadLocals = null;
    inheritedAccessControlContext = null;
    blocker = null;
    uncaughtExceptionHandler = null;
}

/**
 * 强制线程停止执行。
 *
 * 如果安装了安全管理器,则使用<code>this</code>作为参数调用其<code>checkAccess</code>方法。这可能导致(在当前线程中)引发<code>SecurityException</code>。
 *
 * 如果此线程与当前线程不同(即,当前线程试图停止其他线程),还将调用安全管理器的<code>checkPermission</code>方法(使用<code>RuntimePermission("stopThread")</code>参数)。
 * 同样,这可能导致(在当前线程中)抛出<code>SecurityException</code>。
 *
 * 由此线程表示的线程被强制停止其正在进行的任何操作,并抛出一个新创建的<code>ThreadDeath</code>对象作为异常。
 *
 * 允许停止尚未启动的线程。如果最终启动了该线程,则立即终止它。
 *
 * 除非必须执行某些特殊的清理操作(注意,抛出<code>ThreadDeath</code>会导致在线程正式退出之前执行<code>finally</code>子句),
 * 应用程序通常不应该尝试捕获<code>ThreadDeath</code>。<br>
 * 如果<code>catch</code>子句捕获到<code>ThreadDeath</code>对象,重要的是重新抛出该对象,以便线程实际上结束。
 *
 * @exception  SecurityException  如果当前线程不能修改此线程。
 * @see        #interrupt()
 * @see        #checkAccess()
 * @see        #run()
 * @see        #start()
 * @see        ThreadDeath
 * @see        ThreadGroup#uncaughtException(Thread,Throwable)
 * @see        SecurityManager#checkAccess(Thread)
 * @see        SecurityManager#checkPermission
 * @deprecated 此方法本质上是不安全的。使用Thread.stop来停止线程会导致它解锁所有已锁定的监视器(这是未检查的ThreadDeath异常向上传播的自然结果)。
 * 如果任何由这些监视器保护的对象处于不一致状态,则受损对象将对其他线程可见,可能导致任意行为。<br>
 * 许多使用stop的用途应替换为仅修改某些变量以指示目标线程应停止运行。目标线程应定期检查此变量,并在变量指示其应停止运行时从其run方法有序返回。
 * 如果目标线程等待很长时间(例如,在条件变量上),则应使用interrupt方法来中断等待。
 * 有关更多信息,请参见<a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">为什么Thread.stop、Thread.suspend和Thread.resume被弃用?</a>。
 */
@Deprecated
public final void stop() {
    SecurityManager security = System.getSecurityManager();
    if (security != null) {
        checkAccess();
        if (this != Thread.currentThread()) {
            security.checkPermission(SecurityConstants.STOP_THREAD_PERMISSION);
        }
    }
    // 零状态值对应于"NEW",由于持有锁,它不能更改为非"NEW"。
    if (threadStatus != 0) {
        resume(); // 唤醒线程,如果它被挂起,否则无操作
    }

    // VM可以处理所有线程状态
    stop0(new ThreadDeath());
}

/**
 * 抛出<code>UnsupportedOperationException</code>。
 *
 * @param obj 忽略的参数
 *
 * @deprecated 此方法最初设计用于强制线程停止并将给定的<code>Throwable</code>作为异常抛出。它本质上是不安全的(请参见{@link #stop()}的详细信息),
 * 而且还可能用于生成目标线程未准备好处理的异常。<br>
 * 有关更多信息,请参见<a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">为什么Thread.stop、Thread.suspend和Thread.resume被弃用?</a>。
 */
@Deprecated
public final synchronized void stop(Throwable obj) {
    throw new UnsupportedOperationException();
}

/**
 * 中断此线程。
 *
 * 除非当前线程中断自身(始终允许),否则将调用此线程的{@link #checkAccess() checkAccess}方法,
 * 这可能会导致抛出{@link SecurityException}。
 *
 * 如果此线程在{@link Object}类的{@link Object#wait()wait()},{@link Object#wait(long)wait(long)}
 * 或{@link Object#wait(long,int)wait(long,int)}方法的调用中被阻塞或者在此类的{@link #join()},
 * {@link #join(long)},{@link #join(long,int)},{@link #sleep(long)}或{@link #sleep(long,int)} 
 * 方法中被阻塞,则其中断状态将被清除,并且它将收到{@link InterruptedException}。
 *
 * 如果此线程在{@link java.nio.channels.InterruptibleChannel InterruptibleChannel}上
 * 的I / O操作中被阻塞,则通道将关闭,线程的中断状态将被设置,并且线程将收到{@link java.nio.channels.ClosedByInterruptException}。
 *
 * 如果此线程在{@link java.nio.channels.Selector}中被阻塞,则线程的中断状态将被设置,并且它将立即从选择操作返回,
 * 可能带有非零值,就像调用了选择器的{@link java.nio.channels.Selector#wakeup wakeup}方法一样。
 *
 * 如果没有满足前面的条件,则将设置此线程的中断状态。 </p>
 *
 * 中断不是活动的线程可能不会产生任何效果。
 *
 * @throws SecurityException
 *          如果当前线程无法修改此线程
 *
 * @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();
}

/**
 * 测试当前线程是否已中断。 线程的<i>中断状态</ i>由此方法清除。 换句话说,如果连续两次调用此方法,
 * 第二次调用将返回false(除非当前线程在第一次调用清除其中断状态之后并在第二次调用检查其状态之前再次被中断)。
 *
 * 如果在中断时忽略线程中断,此方法将返回false。
 *
 * @return <code>true</ code>如果当前线程已中断; 否则<code> false </ code>。
 * @see #isInterrupted()
 * @revised 6.0
 */
public static boolean interrupted() {
    return currentThread().isInterrupted(true);
}

/**
 * 测试此线程是否已中断。 线程的<i>中断状态</ i>不受此方法的影响。
 *
 * 如果在中断时忽略线程中断,此方法将返回false。
 *
 * @return <code>true</ code>如果此线程已中断; 否则<code> false </ code>。
 * @see #interrupted()
 * @revised 6.0
 */
public boolean isInterrupted() {
    return isInterrupted(false);
}

/**
 * 根据传递的ClearInterrupted值,测试是否有一些线程已中断。根据清除或不清除中断状态进行重置。
 */
private native boolean isInterrupted(boolean ClearInterrupted);

/**
 * 抛出{@link NoSuchMethodError}。
 *
 * @deprecated 此方法最初设计为在没有任何清理的情况下销毁此线程。它持有的任何监视器将保持锁定状态。
 * 但是,该方法从未实施过。如果要实现它,就会以与{@link #suspend}类似的方式容易发生死锁。
 * 如果目标线程在其被销毁时持有保护关键系统资源的锁定,那么没有其他线程可以再次访问此资源。
 * 如果另一个线程试图在调用<code> resume </ code>之前锁定此资源,将导致死锁。这种死锁通常表现为“冻结”进程。
 * 有关更多信息,请参见<a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">
 * 为什么Thread.stop,Thread.suspend和Thread.resume已过时? </a>。
 * @throws NoSuchMethodError始终
 */
@Deprecated
public void destroy() {
    throw new NoSuchMethodError();
}

/**
 * 测试此线程是否处于活动状态。如果线程已启动但尚未终止,则线程处于活动状态。
 *
 * @return <code>true</ code>如果此线程处于活动状态;否则<code> false </ code>。
 */
public final native boolean isAlive();

/**
 * 挂起此线程。
 * 
 * 首先,调用此线程的<code> checkAccess </ code>方法没有参数。这可能导致抛出一个
 * <code> SecurityException </ code>(在当前线程中)。
 * 
 * 如果线程是活动的,则挂起该线程,并且除非恢复,否则不会再取得进展。
 *
 * @exception SecurityException如果当前线程无法修改此线程。
 * @see #checkAccess
 * @deprecated 此方法已被弃用,因为它存在死锁风险。如果目标线程在挂起时持有监视器以保护关键系统资源,
 * 则在目标线程恢复之前,没有线程可以访问此资源。如果试图恢复目标线程的线程在调用<code> resume </ code>之前锁定此监视器,则会发生死锁。
 * 这种死锁通常表现为“冻结”进程。有关更多信息,请参见<a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">
 * 为什么Thread.stop,Thread.suspend和Thread.resume已过时? </a>。
 */
@Deprecated
public final void suspend() {
    checkAccess();
    suspend0();
}

/**
 * 恢复已挂起的线程。
 * 
 * 首先,调用此线程的<code> checkAccess </ code>方法没有参数。这可能导致抛出一个
 * <code> SecurityException </ code>(在当前线程中)。
 * 
 * 如果线程是活动的但被挂起,则恢复该线程,并允许其在执行中取得进展。
 *
 * @exception SecurityException如果当前线程无法修改此线程。
 * @see #checkAccess
 * @see #suspend()
 * @deprecated此方法仅供{@link #suspend}使用,因为它已过时,因为它存在死锁风险。
 * 有关更多信息,请参见<a href="{@docRoot}/../technotes/guides/concurrency/threadPrimitiveDeprecation.html">为什么Thread.stop,
 * Thread.suspend和Thread.resume已过时? </a>。
 */
@Deprecated
public final void resume() {
    checkAccess();
    resume0();
}

/**
 * 更改此线程的优先级。
 * 
 * 首先,调用此线程的<code> checkAccess </ code>方法没有参数。这可能导致抛出一个
 * <code> SecurityException </ code>。
 * 
 * 否则,此线程的优先级设置为指定的<code> newPriority </ code>和线程组的最大允许优先级中较小的那个。
 *
 * @param newPriority要将此线程设置为的优先级
 * @exception IllegalArgumentException如果优先级不在<code> MIN_PRIORITY </ code>到<code> MAX_PRIORITY </ code>范围内。
 * @exception SecurityException如果当前线程无法修改此线程。
 * @see #getPriority
 * @see #checkAccess()
 * @see #getThreadGroup()
 * @see #MAX_PRIORITY
 * @see #MIN_PRIORITY
 * @see ThreadGroup#getMaxPriority()
 */
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);
    }
}

/**
 * 返回此线程的优先级。
 *
 * @return此线程的优先级。
 * @see #setPriority
 */
public final int getPriority() {
    return priority;
}

/**
 * 将此线程的名称更改为与参数<code> name </ code>相等。
 * 
 * 首先,调用此线程的<code> checkAccess </ code>方法没有参数。这可能导致抛出一个
 * <code> SecurityException </ code>。
 *
 * @param name此线程的新名称。
 * @exception SecurityException如果当前线程无法修改此线程。
 * @see #getName
 * @see #checkAccess()
 */
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);
    }
}

/**
 * 返回此线程的名称。
 *
 * @return此线程的名称。
 * @see #setName(String)
 */
public final String getName() {
    return name;
}

/**
 * 返回此线程所属的线程组。 如果此线程已死(已停止),则此方法返回null。
 *
 * @return此线程的线程组。
 */
public final ThreadGroup getThreadGroup() {
    return group;
}

/**
 * 返回当前线程的{@linkplain java.lang.ThreadGroup线程组}及其子组中活动线程的估计数量。
 * 递归地遍历当前线程的线程组中的所有子组。
 *
 * 返回的值仅是一个估计值,因为线程的数量可能在此方法遍历内部数据结构时动态更改,
 * 并且可能受到某些系统线程的影响。 此方法主要用于调试和监视目的。
 *
 * @return当前线程的线程组中以及将当前线程的线程组作为祖先的任何其他线程组中活动线程数量的估计值
 */
public static int activeCount() {
    return currentThread().getThreadGroup().activeCount();
}

/**
 * 将当前线程的线程组和其子组中的每个活动线程复制到指定的数组中。该方法只是调用当前线程的线程组的{@link java.lang.ThreadGroup#enumerate(Thread [])}方法。
 *
 *  应用程序可以使用{@linkplain #activeCount activeCount}方法来估算数组的大小,
 * 但是,<i>如果数组太短而无法容纳所有线程,则会静默忽略额外的线程。</i> 如果获取当前线程的线程组及其子组中的每个活动线程非常重要,
 * 调用者应验证返回的int值是否严格小于{@code tarray}的长度。
 *
 *  由于此方法中固有的竞态条件,建议仅将此方法用于调试和监视目的。
 *
 * @param  tarray
 *         用于放置线程列表的数组
 *
 * @return  放入数组中的线程数
 *
 * @throws  SecurityException
 *          如果{@link java.lang.ThreadGroup#checkAccess}确定当前线程无法访问其线程组
 */
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}表示永远等待。
 *
 *  此实现使用了一系列基于{@code this.wait}调用的循环,条件是{@code this.isAlive}。 当线程终止时,
 * 将调用{@code this.notifyAll}方法。 建议应用程序不要在{@code Thread}实例上使用{@code wait},
 * {@code notify}或{@code notifyAll}。
 *
 * @param  millis
 *         要等待的时间(以毫秒为单位)
 *
 * @throws  IllegalArgumentException
 *          如果{@code millis}的值为负
 *
 * @throws  InterruptedException
 *          如果任何线程中断了当前线程。 当抛出此异常时,当前线程的<i>中断状态</ i>将被清除。
 */
public final synchronized void join(long millis)
throws InterruptedException {
    long base = System.currentTimeMillis();
    long now = 0;

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

    if (millis == 0) {
        while (isAlive()) {
            wait(0);
        }
    } else {
        while (isAlive()) {
            long delay = millis - now;
            if (delay <= 0) {
                break;
            }
            wait(delay);
            now = System.currentTimeMillis() - base;
        }
    }
}

/**
 * 等待最多{@code millis}毫秒加上{@code nanos}纳秒,直到此线程死亡。
 *
 *  此实现使用了一系列基于{@code this.wait}调用的循环,条件是{@code this.isAlive}。 当线程终止时,
 * 将调用{@code this.notifyAll}方法。 建议应用程序不要在{@code Thread}实例上使用{@code wait},
 * {@code notify}或{@code notifyAll}。
 *
 * @param  millis
 *         要等待的时间(以毫秒为单位)
 *
 * @param  nanos
 *         {@code 0-999999}额外的纳秒等待时间
 *
 * @throws  IllegalArgumentException
 *          如果{@code millis}的值为负,或者{@code nanos}的值不在{@code 0-999999}范围内
 *
 * @throws  InterruptedException
 *          如果任何线程中断了当前线程。 当抛出此异常时,当前线程的<i>中断状态</ i>将被清除。
 */
public final synchronized void join(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++;
    }

    join(millis);
}

/**
 * 等待此线程死亡。
 *
 *  此方法的调用方式与调用方式完全相同
 *
 * <blockquote>
 * {@linkplain #join(long) join}{@code (0)}
 * </blockquote>
 *
 * @throws  InterruptedException
 *          如果任何线程中断了当前线程。 当抛出此异常时,当前线程的<i>中断状态</ i>将被清除。
 */
public final void join() throws InterruptedException {
    join(0);
}

/**
 * 将当前线程的堆栈跟踪打印到标准错误流。 此方法仅用于调试。
 *
 * @see     Throwable#printStackTrace()
 */
public static void dumpStack() {
    new Exception("Stack trace").printStackTrace();
}

/**
 * 将此线程标记为{@linkplain #isDaemon守护程序}线程或用户线程。 当只有所有运行的线程都是守护线程时,
 * Java虚拟机退出。
 *
 *  必须在启动线程之前调用此方法。
 *
 * @param  on
 *         如果{@code true},则将此线程标记为守护线程
 *
 * @throws  IllegalThreadStateException
 *          如果此线程是{@linkplain #isAlive alive}
 *
 * @throws  SecurityException
 *          如果{@link #checkAccess}确定当前线程无法修改此线程
 */
public final void setDaemon(boolean on) {
    checkAccess();
    if (isAlive()) {
        throw new IllegalThreadStateException();
    }
    daemon = on;
}

/**
 * 测试此线程是否为守护线程。
 *
 * @return  <code>true</code>如果此线程是守护线程;否则<code>false</code>。
 * @see     #setDaemon(boolean)
 */
public final boolean isDaemon() {
    return daemon;
}

/**
 * 确定当前运行的线程是否具有修改此线程的权限。
 * 
 * 如果存在安全管理器,则将调用其{@code checkAccess}方法,该方法以此线程作为其参数。 这可能会导致抛出一个{@code SecurityException}。
 *
 * @exception  SecurityException  如果当前线程不允许访问此线程。
 * @see        SecurityManager#checkAccess(Thread)
 */
public final void checkAccess() {
    SecurityManager security = System.getSecurityManager();
    if (security != null) {
        security.checkAccess(this);
    }
}

/**
 * 返回此线程的字符串表示形式,包括线程的名称、优先级和线程组。
 *
 * @return  此线程的字符串表示形式。
 */
public String toString() {
    ThreadGroup group = getThreadGroup();
    if (group != null) {
        return "Thread[" + getName() + "," + getPriority() + "," +
                       group.getName() + "]";
    } else {
        return "Thread[" + getName() + "," + getPriority() + "," +
                        "" + "]";
    }
}

/**
 * 返回此线程的上下文类加载器。 上下文类加载器由创建线程的对象提供,
 * 以便在该线程中运行的代码在加载类和资源时使用。 如果未设置(通过{@code setContextClassLoader}),
 * 则默认为父线程的类加载器上下文。 原始线程的上下文类加载器通常设置为用于加载应用程序的类加载器。
 *
 *  如果存在安全管理器,并且调用者的类加载器不是{@code null},并且与上下文类加载器不同也不是其祖先,则此方法将使用运行时权限
 * {@link RuntimePermission}({@code "getClassLoader"})调用安全管理器的{@link SecurityManager#checkPermission(java.security.Permission) checkPermission}方法,
 * 以验证是否允许检索上下文类加载器。
 *
 * @return  此线程的上下文类加载器,如果返回{@code null},则表示系统类加载器(如果失败,则为引导类加载器)
 *
 * @throws  SecurityException
 *          如果当前线程无法获取上下文类加载器
 *
 * @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;
}

/**
 * 设置此线程的上下文类加载器。 上下文类加载器可以在创建线程时设置,并允许创建线程的对象通过{@code getContextClassLoader}
 * 向在线程中运行的代码提供适当的类加载器。 
 * 如果存在安全管理器,则将使用运行时权限{@link RuntimePermission}({@code "setContextClassLoader"})调用其
 * {@link SecurityManager#checkPermission(java.security.Permission) checkPermission}方法,
 * 以检查是否允许设置上下文类加载器。
 *
 * @param  cl
 *         此线程的上下文类加载器,如果返回null,则表示系统类加载器(或者如果失败,则引导类加载器)
 *
 * @throws  SecurityException
 *          如果当前线程无法设置上下文类加载器
 *
 * @since 1.2
 */
public void setContextClassLoader(ClassLoader cl) {
    SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
        sm.checkPermission(new RuntimePermission("setContextClassLoader"));
    }
    contextClassLoader = cl;
}

/**
 * 当前线程是否持有对指定对象的监视器锁。
 *
 * 此方法旨在允许程序断言当前线程已经持有指定的锁:
 * <pre>
 *     assert Thread.holdsLock(obj);
 * </pre>
 *
 * @param  obj 要测试锁所有权的对象
 * @throws NullPointerException 如果obj为<tt>null</tt>
 * @return 如果当前线程持有指定对象的监视器锁,则为<tt>true</tt>。
 * @since 1.4
 */
public static native boolean holdsLock(Object obj);

private static final StackTraceElement[] EMPTY_STACK_TRACE
    = new StackTraceElement[0];

/**
 * 返回表示此线程的堆栈转储的堆栈跟踪元素数组。如果此线程尚未启动,已启动但尚未由系统调度运行,或者已终止,则此方法将返回一个长度为零的数组。
 * 如果返回的数组长度非零,则数组的第一个元素表示堆栈的顶部,即序列中最近的方法调用。数组的最后一个元素表示堆栈的底部,即序列中最早的方法调用。
 *
 * 如果存在安全管理器,并且此线程不是当前线程,则将使用运行时权限`RuntimePermission("getStackTrace")`调用安全管理器的`checkPermission`方法,
 * 以查看是否允许获取堆栈跟踪。
 *
 * 在某些情况下,某些虚拟机可能会省略一个或多个堆栈帧的堆栈跟踪。在极端情况下,如果虚拟机没有关于此线程的堆栈跟踪信息,则允许从此方法返回长度为零的数组。
 *
 * @return 代表一个堆栈帧的堆栈跟踪元素数组。
 *
 * @throws SecurityException
 *         如果存在安全管理器并且其`checkPermission`方法不允许获取线程的堆栈跟踪。
 * @see SecurityManager#checkPermission
 * @see RuntimePermission
 * @see Throwable#getStackTrace
 *
 * @since 1.5
 */
public StackTraceElement[] getStackTrace() {}

/**
 * 返回所有活动线程的堆栈跟踪映射。映射的键是线程,每个映射值是一个`StackTraceElement`数组,表示相应线程的堆栈转储。
 * 返回的堆栈跟踪以`getStackTrace`方法指定的格式呈现。
 *
 * 在调用此方法时,线程可能正在执行。每个线程的堆栈跟踪仅表示快照,并且可以在不同的时间获取每个堆栈跟踪。如果虚拟机对线程没有堆栈跟踪信息,则在映射值中返回零长度的数组。
 *
 * 如果存在安全管理器,则将使用运行时权限`RuntimePermission("getStackTrace")`和`RuntimePermission("modifyThreadGroup")`调用安全管理器的`checkPermission`方法,
 * 以查看是否允许获取所有线程的堆栈跟踪。
 *
 * @return 从`Thread`到`StackTraceElement`数组的映射,表示相应线程的堆栈跟踪。
 *
 * @throws SecurityException
 *         如果存在安全管理器并且其`checkPermission`方法不允许获取线程的堆栈跟踪。
 * @see #getStackTrace
 * @see SecurityManager#checkPermission
 * @see RuntimePermission
 * @see Throwable#getStackTrace
 *
 * @since 1.5
 */
public static Map<Thread, StackTraceElement[]> getAllStackTraces() {}

/**
 * 返回此线程的标识符。线程ID是在创建此线程时生成的一个正数长整型数字。线程ID是唯一的,并且在其生命周期内保持不变。当线程终止时,此线程ID可能会被重用。
 *
 * @return 此线程的ID。
 * @since 1.5
 */
public long getId() {}

/**
 * 线程状态。线程可以处于以下状态之一:
 *
 * - `NEW`:尚未启动的线程。
 * - `RUNNABLE`:在Java虚拟机中执行的线程。
 * - `BLOCKED`:阻塞等待监视器锁的线程。
 * - `WAITING`:等待其他线程执行特定操作的线程。
 * - `TIMED_WAITING`:等待其他线程执行特定操作的线程,但有一个指定的等待时间。
 * - `TERMINATED`:已退出的线程。
 *
 * 线程在某一时刻只能处于一个状态。这些状态是虚拟机状态,不反映任何操作系统线程状态。
 *
 * @since 1.5
 * @see #getState
 */
public enum State {
    /**
     * 尚未启动的线程的线程状态。
     */
    NEW,

    /**
     * 可运行线程的线程状态。运行中的线程在Java虚拟机中执行,但可能正在等待操作系统的其他资源(如处理器)。
     */
    RUNNABLE,

    /**
     * 等待获取监视器锁的线程的线程状态。
     * 处于阻塞状态的线程正在等待获取监视器锁,以进入同步块/方法,或在调用Object.wait()后重新进入同步块/方法。
     */
    BLOCKED,

    /**
     * 等待状态的线程的线程状态。
     * 由于调用某些方法,线程处于等待状态:
     *
     * - Object.wait()(无超时)
     * - Thread.join()(无超时)
     * - LockSupport.park()
     *
     * 等待状态的线程正在等待另一个线程执行特定操作。
     * 例如,调用了Object.wait()的线程正在等待另一个线程调用Object.notify()或Object.notifyAll()来唤醒它。
     * 调用了Thread.join()的线程正在等待指定的线程终止。
     */
    WAITING,

    /**
     * 具有指定等待时间的等待状态的线程的线程状态。
     * 由于调用某些方法,并指定了正值的等待时间,线程处于定时等待状态:
     *
     * - Thread.sleep()
     * - Object.wait(long)(超时)
     * - Thread.join(long)(超时)
     * - LockSupport.parkNanos()
     * - LockSupport.parkUntil()
     */
    TIMED_WAITING,

    /**
     * 终止的线程的线程状态。
     * 线程已经完成执行。
     */
    TERMINATED;
}

/**
 * 返回此线程的状态。
 * 此方法设计用于监视系统状态,而不是用于同步控制。
 *
 * @return 此线程的状态。
 * @since 1.5
 */
public State getState() {
    // 获取当前线程的状态
    return sun.misc.VM.toThreadState(threadStatus);
}

// JSR-166新增

/**
 * 当线程由于未捕获的异常而突然终止时调用的处理程序接口。
 * 当一个线程即将由于未捕获的异常而终止时,Java虚拟机将使用线程的`getUncaughtExceptionHandler`方法查询线程的`UncaughtExceptionHandler`,
 * 并调用处理程序的`uncaughtException`方法,传递线程和异常作为参数。
 * 如果一个线程没有显式设置其`UncaughtExceptionHandler`,则其`ThreadGroup`对象将充当其`UncaughtExceptionHandler`。
 * 如果`ThreadGroup`对象对于处理异常没有特殊要求,则它可以将调用转发给{@linkplain #getDefaultUncaughtExceptionHandler默认的未捕获异常处理程序}。
 *
 * @see #setDefaultUncaughtExceptionHandler
 * @see #setUncaughtExceptionHandler
 * @see ThreadGroup#uncaughtException
 * @since 1.5
 */
@FunctionalInterface
public interface UncaughtExceptionHandler {
    /**
     * 当给定线程由于给定未捕获的异常而终止时调用的方法。
     * 此方法抛出的任何异常都将被Java虚拟机忽略。
     * @param t 线程
     * @param e 异常
     */
    void uncaughtException(Thread t, Throwable e);
}

// 除非显式设置,否则为null
private volatile UncaughtExceptionHandler uncaughtExceptionHandler;

// 除非显式设置,否则为null
private static volatile UncaughtExceptionHandler defaultUncaughtExceptionHandler;

/**
 * 设置线程突然终止时调用的默认处理程序,如果该线程没有定义其他处理程序。
 *
 * 未捕获的异常处理首先由线程本身控制,然后由线程的{@link ThreadGroup}对象控制,最后由默认的未捕获异常处理程序控制。
 * 如果线程没有显式设置未捕获的异常处理程序,并且线程的线程组(包括父线程组)没有专门指定其`uncaughtException`方法,则将调用默认处理程序的`uncaughtException`方法。
 * 通过设置默认的未捕获异常处理程序,应用程序可以更改对于那些已经接受系统提供的“默认”行为的线程来说,未捕获异常如何处理(例如,记录到特定设备或文件)。
 *
 * 请注意,默认的未捕获异常处理程序通常不应推迟到线程的`ThreadGroup`对象,因为这可能导致无限递归。
 *
 * @param eh 用作默认未捕获异常处理程序的对象。如果为`null`,则没有默认处理程序。
 *
 * @throws SecurityException 如果存在安全管理器并且它拒绝`{@link RuntimePermission}("setDefaultUncaughtExceptionHandler")`
 *
 * @see #setUncaughtExceptionHandler
 * @see #getUncaughtExceptionHandler
 * @see ThreadGroup#uncaughtException
 * @since 1.5
 */
public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler eh) {
    SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
        sm.checkPermission(new RuntimePermission("setDefaultUncaughtExceptionHandler"));
    }
    defaultUncaughtExceptionHandler = eh;
}

/**
 * 返回线程突然终止时调用的默认处理程序。如果返回值为`null`,则没有默认处理程序。
 * @since 1.5
 * @see #setDefaultUncaughtExceptionHandler
 * @return 所有线程的默认未捕获异常处理程序
 */
public static UncaughtExceptionHandler getDefaultUncaughtExceptionHandler(){
    return defaultUncaughtExceptionHandler;
}

/**
 * 返回当此线程由于未捕获的异常而突然终止时调用的处理程序。如果此线程尚未显式设置未捕获的异常处理程序,则返回此线程的`ThreadGroup`对象,
 * 除非此线程已经终止,在这种情况下返回`null`。
 * @since 1.5
 * @return 此线程的未捕获异常处理程序
 */
public UncaughtExceptionHandler getUncaughtExceptionHandler() {
    return uncaughtExceptionHandler != null ? uncaughtExceptionHandler : group;
}

/**
 * 设置当此线程由于未捕获的异常而突然终止时调用的处理程序。
 * 线程可以通过显式设置其未捕获的异常处理程序,完全控制其对未捕获异常的响应。
 * 如果没有设置这样的处理程序,则线程的`ThreadGroup`对象将充当其处理程序。
 * @param eh 用作此线程未捕获的异常处理程序的对象。如果为`null`,则此线程没有显式处理程序。
 * @throws  SecurityException 如果当前线程不允许修改此线程。
 * @see #setDefaultUncaughtExceptionHandler
 * @see ThreadGroup#uncaughtException
 * @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);
    }
}

/**
 * 弱引用类对象的弱键。
 **/
static class WeakClassKey extends WeakReference<Class<?>> {
    /**
     * 保存原始引用对象的标识哈希码的值,在引用对象被清除后保持一致的哈希码。
     */
    private final int hash;

    /**
     * 创建一个新的WeakClassKey,将其注册到队列中。
     */
    WeakClassKey(Class<?> cl, ReferenceQueue<Class<?>> refQueue) {
        super(cl, refQueue);
        hash = System.identityHashCode(cl);
    }

    /**
     * 返回原始引用对象的标识哈希码。
     */
    @Override
    public int hashCode() {
        return hash;
    }

    /**
     * 如果给定对象是此相同的WeakClassKey实例,则返回true,
     * 或者如果该对象的引用对象尚未清除,并且给定对象是另一个具有与此对象相同的非空引用对象的WeakClassKey实例,则返回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专门管理。
// 这些字段用于在并发代码中构建高性能PRNG,并且我们不能冒险发生意外的错误共享。
// 因此,这些字段被@Contended隔离。

/** ThreadLocalRandom的当前种子 */
@sun.misc.Contended("tlr")
long threadLocalRandomSeed;

/** Probe哈希值;如果threadLocalRandomSeed已初始化,则不为零 */
@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);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BigDataMLApplication

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值