继承关系
先看源码:Thread 类实现了 Runnable 接口
publicclass Thread implements Runnable {
而 Runnable 被@FunctionalInterface 注解标记为函数式接口,Runnable 接口源代码
@FunctionalInterfacepublic interface Runnable {public abstract void run();}
再来看看@FunctionalInterface 注解的源码
@Documented@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)public @interface FunctionalInterface {}
FunctionalInterface 用于标记类或接口是否是一个函数式接口,并在运行时可用于反射获取信息。
Thread 类源码解析
加载本地资源
private static native void registerNatives();static {registerNatives();}
这段代码是 Thread 类的一个静态初始化块。它包含了两个关键的部分:registerNatives() 方法和静态初始化块。
registerNatives() 方法:
registerNatives() 是一个本地方法,即它是用本地代码(通常是用 C 或 C++ 编写的)实现的方法。这个方法的作用是在本地操作系统层面注册和初始化与 Thread 类相关的资源和功能。具体而言,这个方法会与底层操作系统的线程管理机制进行交互,以实现 Java 线程在操作系统层面的创建、销毁等操作。
静态初始化块:
static 关键字表示这是一个静态初始化块,它在类加载时会被执行,且仅执行一次。在这个静态初始化块中,通过调用 registerNatives() 方法来注册本地方法。这确保了在使用 Thread 类之前,与底层操作系统的交互机制已经准备就绪。
成员变量
private volatile String name;这是 Thread 类中的一个私有字段,用于存储线程的名称。volatile 关键字表示这个字段是易变的(volatile),这意味着多个线程可以在没有锁的情况下进行访问。线程的名称可以通过 getName() 和 setName() 方法进行读取和设置。private intpriority;这是线程的优先级字段,用于存储线程的优先级。优先级是一个整数,表示线程在竞争 CPU 时间时的相对优先级。线程的优先级可以通过 getPriority() 和 setPriority() 方法进行读取和设置。private Thread threadQ;这是一个字段,用于存储线程的线程组。线程组是一种用于组织和管理一组相关线程的机制。一个线程可以属于一个线程组,这有助于线程的管理和资源分配。线程的线程组可以通过 getThreadGroup() 方法获得。private long eetop;这是一个字段,用于存储 Java 线程本地存储(JVM Thread Local Storage)的起始地址。线程本地存储是一种机制,允许每个线程存储自己的数据,不与其他线程共享。这个字段通常由 JVM 内部使用,与线程的运行状态相关。/* 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 */private boolean stillborn = false;这个字段存储线程要执行的任务,通常是一个实现了 Runnable 接口的对象。当线程启动时,它会执行 target 的 run() 方法。/* What will be run. */private Runnable target;这个字段用于标记线程是否是“仍然出生”的。在 Thread 类的构造函数中,如果线程创建失败,则会将 stillborn 标记为 true,否则为 false。这个字段在异常情况下有用,用于标记线程是否成功创建。/* The group of this thread */private ThreadGroup group;这个字段存储线程所属的线程组。线程组是一种用于组织和管理一组相关线程的机制。一个线程可以属于一个线程组,这有助于线程的管理和资源分配。private ClassLoader contextClassLoader;这个字段存储线程的上下文类加载器(Context ClassLoader)。每个线程可以有自己的类加载器,用于加载线程所需的类和资源。private AccessControlContext inheritedAccessControlContext;这个字段存储线程的继承的访问控制上下文。它是一个安全相关的概念,用于控制线程对于敏感资源的访问权限。private static int threadInitNumber;这是一个静态字段,用于为新线程分配唯一的标识号。每次创建一个新的线程时,这个字段会被递增,从而确保每个线程都有不同的标识号。ThreadLocal.ThreadLocalMap threadLocals = null;这个字段用于存储线程的本地变量(ThreadLocal variables)。每个线程可以通过 ThreadLocal 对象创建和管理自己的本地变量。ThreadLocalMap 是一个用于存储本地变量的数据结构,其中的键是 ThreadLocal 对象,值是本地变量的值。ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;类似于上面的 threadLocals 字段,但这个字段用于存储可以被子线程继承的本地变量。ThreadLocalMap 是一个用于存储这些继承变量的数据结构。private long stackSize;这个字段存储线程的栈大小。栈是用于存储方法调用、局部变量和方法执行状态的内存区域。private long nativeParkEventPointer;这个字段用于存储一个指针,用于与底层操作系统的事件(event)相关联。这个字段通常在与线程的等待和阻塞操作相关的情况下使用。private long tid;这个字段存储线程的唯一标识号(Thread ID)。每个线程在操作系统层面都有一个唯一的标识号,可以用于识别不同的线程。private static long threadSeqNumber;这个字段是一个静态字段,用于为新线程分配唯一的序列号。类似于 threadInitNumber,但是更为细粒度,可以用于生成更详细的线程标识。private volatile int threadStatus = 0;这个字段用于存储线程的状态。volatile 关键字确保了线程间的可见性,这是因为线程的状态可能在不同的线程之间变化。线程状态可能包括 NEW(新建)、RUNNABLE(运行中)、BLOCKED(阻塞中)、WAITING(等待中)、TIMED_WAITING(有限时间等待中)和 TERMINATED(终止)。volatile Object parkBlocker;这个字段用于存储线程在等待状态(parked)时的阻塞对象(Blocker)。阻塞对象表示导致线程进入等待状态的原因,当线程被阻塞时,这个字段会被设置为相应的阻塞对象。private volatile Interruptible blocker;这个字段存储一个中断对象(Interruptible),用于在线程阻塞时检测中断并响应。它用于中断一个阻塞的线程,使其退出等待状态。private final Object blockerLock = new Object(); 这个字段是一个用于同步的锁对象,用于保护 blocker 字段的访问和修改。在多线程环境中,blocker 字段的访问需要进行同步,以避免竞争条件。public final static int MIN_PRIORITY = 1;这是一个表示线程最低优先级的常量。在 Java 中,线程优先级的范围是从 MIN_PRIORITY 到 MAX_PRIORITY,优先级越高的线程在竞争 CPU 时间时有更高的几率被执行。public final static int NORM_PRIORITY = 5;这是一个表示线程默认优先级的常量。通常情况下,线程的默认优先级是 NORM_PRIORITY,这个值在优先级范围内位于中间。public final static int MAX_PRIORITY = 10;这是一个表示线程最高优先级的常量。与 MIN_PRIORITY 相对应,线程优先级的范围是从 MIN_PRIORITY 到 MAX_PRIORITY,优先级越高的线程在竞争 CPU 时间时有更高的几率被执行。private static final StackTraceElement[] EMPTY_STACK_TRACE= new StackTraceElement[0];这个字段是一个用于表示空的堆栈轨迹元素数组。在某些情况下,当获取线程的堆栈轨迹时,如果堆栈为空,就会使用这个空数组作为结果。private static final RuntimePermission SUBCLASS_IMPLEMENTATION_PERMISSION =new RuntimePermission("enableContextClassLoaderOverride");这个字段是一个 RuntimePermission 对象,用于表示允许子类覆盖 Thread 类的上下文类加载器的权限。上下文类加载器允许线程在运行时加载类和资源。private volatile UncaughtExceptionHandler uncaughtExceptionHandler;这个字段用于存储线程的未捕获异常处理器(UncaughtExceptionHandler)。当线程中未捕获的异常导致线程终止时,会调用该处理器来处理异常情况。private static volatile UncaughtExceptionHandler defaultUncaughtExceptionHandler;这个字段用于存储默认的未捕获异常处理器,适用于所有线程。当线程没有指定自己的未捕获异常处理器时,将会使用默认的处理器。@sun.misc.Contended("tlr")long threadLocalRandomSeed;这个字段存储线程本地随机数生成器的种子,用于生成随机数。@sun.misc.Contended 是一个注解,用于提示 JVM 在编译时对字段进行填充,以避免伪共享(false sharing)的问题。@sun.misc.Contended("tlr")int threadLocalRandomProbe;类似于上面的 threadLocalRandomSeed,这个字段用于存储线程本地随机数生成器的探测值。@sun.misc.Contended("tlr")int threadLocalRandomSecondarySeed;类似于上面的字段,这个字段存储线程本地随机数生成器的辅助种子。
方法
构造方法
public Thread() {init(null, null, "Thread-" + nextThreadNum(), 0);}public Thread(Runnable target) {init(null, target, "Thread-" + nextThreadNum(), 0);}Thread(Runnable target, AccessControlContext acc) {init(null, target, "Thread-" + nextThreadNum(), 0, acc, false);}public Thread(ThreadGroup group, Runnable target) {init(group, target, "Thread-" + nextThreadNum(), 0);}public Thread(String name) {init(null, null, name, 0);}public Thread(ThreadGroup group, String name) {init(group, null, name, 0);}public Thread(Runnable target, String name) {init(null, target, name, 0);}public Thread(ThreadGroup group, Runnable target, String name) {init(group, target, name, 0);}public Thread(ThreadGroup group, Runnable target, String name,long stackSize) {init(group, target, name, stackSize);}
可见构造方法都是调用的这个
private void init(ThreadGroup g, Runnable target, String name,long stackSize) {init(g, target, name, stackSize, null, true);}
接着调用这个
private void init(ThreadGroup g, Runnable target, String name,long stackSize, AccessControlContext acc,boolean inheritThreadLocals) {if (name == null) {// 检查名称是否为空: 首先,方法检查传入的线程名称 name 是否为空,如果为空则抛出一个空指针异常。throw new NullPointerException("name cannot be null");}// 设置线程名称: 将传入的线程名称 name 设置给当前线程实例的 name 属性。this.name = name;// 获取当前线程和安全管理器: 获取当前线程的实例和安全管理器的实例。Thread parent = currentThread();SecurityManager security = System.getSecurityManager();// 设置线程组: 如果传入的线程组 g 为 null,会根据安全管理器和当前线程的信息获取一个线程组实例。然后,对获取的线程组进行访问权限检查。if (g == null) {if (security != null) {g = security.getThreadGroup();}if (g == null) {g = parent.getThreadGroup();}}g.checkAccess();//// 安全管理器权限检查: 如果安全管理器存在,并且当前线程的子类重写了 getContextClassLoader() 方法,会检查权限。if (security != null) {if (isCCLOverridden(getClass())) {security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);}}// 将线程设置为未启动状态: 调用线程组的 addUnstarted() 方法,将线程状态设置为未启动。g.addUnstarted();// 设置线程的属性: 设置线程实例的各个属性,包括线程组、守护线程状态、优先级、上下文类加载器等。this.group = g;this.daemon = parent.isDaemon();this.priority = parent.getPriority(); if (security == null || isCCLOverridden(parent.getClass()))this.contextClassLoader = parent.getContextClassLoader();elsethis.contextClassLoader = parent.contextClassLoader;this.inheritedAccessControlContext =acc != null ? acc : AccessController.getContext();this.target = target;setPriority(priority); // 设置继承的线程局部变量: 如果 inheritThreadLocals 为 true,且父线程的可继承线程局部变量不为空,会创建继承的线程局部变量映射。if (inheritThreadLocals && parent.inheritableThreadLocals != null)this.inheritableThreadLocals =ThreadLocal.createInheritedMap(parent.inheritableThreadLocals); // 设置线程栈大小: 设置线程的栈大小。 this.stackSize = stackSize;// 生成线程 ID: 根据方法 nextThreadID() 生成线程的 ID。tid = nextThreadID();}
这是 Java 中 Thread 类中的一个私有方法 init,用于初始化线程实例的各个属性。让我们逐步解释这个方法的内容:
检查名称是否为空: 首先,方法检查传入的线程名称 name 是否为空,如果为空则抛出一个空指针异常。设置线程名称: 将传入的线程名称 name 设置给当前线程实例的 name 属性。获取当前线程和安全管理器: 获取当前线程的实例和安全管理器的实例。设置线程组: 如果传入的线程组 g 为 null,会根据安全管理器和当前线程的信息获取一个线程组实例。然后,对获取的线程组进行访问权限检查。安全管理器权限检查: 如果安全管理器存在,并且当前线程的子类重写了 getContextClassLoader() 方法,会检查权限。将线程设置为未启动状态: 调用线程组的 addUnstarted() 方法,将线程状态设置为未启动。设置线程的属性: 设置线程实例的各个属性,包括线程组、守护线程状态、优先级、上下文类加载器等。设置继承的线程局部变量: 如果 inheritThreadLocals 为 true,且父线程的可继承线程局部变量不为空,会创建继承的线程局部变量映射。设置线程栈大小: 设置线程的栈大小。生成线程 ID: 根据方法 nextThreadID() 生成线程的 ID。
总之,这个 init 方法用于初始化线程实例的各个属性,包括线程组、名称、优先级、守护状态等,还会进行一些权限检查和设置。这些属性会在线程启动时用于线程的运行。
其他方法
private static synchronized int nextThreadNum() {return threadInitNumber++;}
它使用了 synchronized 关键字,意味着在多线程环境下只有一个线程能够访问这个方法,以保证线程安全。
threadInitNumber 是一个静态变量,用于记录线程的初始编号。
++ 操作符用于递增 threadInitNumber,然后返回递增前的值作为当前线程的编号。
所以,每次调用 nextThreadNum() 方法时,都会返回一个唯一递增的整数,用于生成线程名称。
private static synchronized long nextThreadID() {return ++threadSeqNumber;}
threadSeqNumber 是一个静态变量,用于记录线程的序列号。
++ 操作符用于递增 threadSeqNumber,然后返回递增后的值作为当前线程的唯一标识。
void blockedOn(Interruptible b) {synchronized (blockerLock) {blocker = b;}}
用于将当前线程标记为在某个可中断的操作(Interruptible)上阻塞。
Interruptible 是一个接口或类,表示可以被中断的操作,可能是 I/O 操作或其他需要阻塞线程的操作。blockerLock 是一个对象,用于同步操作,以确保线程访问 blocker 变量的线程安全性。blocker 是一个实例变量,用于存储当前线程正在阻塞在哪个可中断的操作上。
这个方法的作用是将当前线程标记为阻塞在某个特定的可中断操作上。在多线程环境中,一个线程可能因为等待某些资源或执行某些操作而被阻塞。通过调用 blockedOn 方法并传递一个 Interruptible 对象,可以记录下当前线程阻塞的原因,以便后续可以对其进行中断操作。
public static native Thread currentThread();
这个方法返回当前正在执行的线程的实例。通过调用这个方法,可以获取当前代码块或方法正在运行的线程实例。
public static native void yield();
这个方法是一个线程调度方法,它暗示调度器可以将当前线程切换出去,让其他线程有机会运行。yield 方法的调用可能会导致当前线程进入就绪状态,然后调度器决定下一个要运行的线程。
public static native void sleep(long millis) throws InterruptedException;
这个方法用于使当前线程进入休眠状态,让出 CPU 资源给其他线程。它的参数 millis 表示线程休眠的毫秒数。线程会进入休眠状态,等待一段时间后自动唤醒。如果在线程休眠过程中发生中断,会抛出 InterruptedException 异常。
public static void sleep(long millis, int nanos)throws InterruptedException {if (millis < 0) {throw new IllegalArgumentException("timeout value is negative");}if (nanos 999999) {throw new IllegalArgumentException("nanosecond timeout value out of range");}if (nanos >= 500000 || (nanos != 0 && millis == 0)) {millis++;}sleep(millis);}
首先,代码对参数进行了检查。如果 millis 小于 0 或者 nanos 不在合理的范围内(0 到 999999),会抛出 IllegalArgumentException 异常。
接着,代码对 nanos 进行了调整。如果 nanos 大于等于 500000 或者 nanos 不为 0 且 millis 为 0,会将 millis 加 1,以确保休眠时间的准确性。
最后,代码调用了 sleep(millis) 方法,将线程休眠 millis 毫秒的时间。如果有额外的 nanos 参数,它会影响到休眠时间的纳秒部分。
总的来说,这个方法是 Thread 类的一个休眠方法的实现,允许指定毫秒数和纳秒数作为休眠时间。注意,线程休眠可能会被中断,从而抛出 InterruptedException 异常。
@Overrideprotected Object clone() throws CloneNotSupportedException {throw new CloneNotSupportedException();}
它重写了父类 Object 的 clone() 方法,并在方法体内抛出了 CloneNotSupportedException 异常,表示该类不支持克隆操作。
@Override:这是一个注解,表示这个方法是对父类中同名方法的重写。
protected Object clone():
这是重写的方法签名。它返回一个 Object 类型的对象,表示克隆后的副本。
throws CloneNotSupportedException:这是方法的声明,表示这个方法可能会抛出 CloneNotSupportedException 异常,这是一个标准异常类,表示对象不支持克隆。
方法体内部只有一行代码,就是抛出 CloneNotSupportedException 异常,意味着无法进行克隆操作。
总的来说,这段代码阻止了 Thread 类的实例被克隆。由于线程是一个底层资源,直接克隆线程实例可能会导致意外和不一致的行为,因此该方法抛出异常以防止此类操作。
public synchronized void start() { 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) {}}}
它做了以下事情:
检查线程状态是否为0(即新建状态),如果不是,则抛出IllegalThreadStateException异常。将当前线程添加到线程组。尝试调用 start0() 方法启动线程,并将 started 设置为 true 表示启动成功。如果启动失败(started 为 false),则通过 group.threadStartFailed(this) 通知线程组。这段代码确保线程在适当的状态下启动,并根据启动结果通知线程组。
private native void start0();
这行代码 private native void start0(); 表示一个 Java 方法的声明,但其具体实现是在本地方法中。这意味着该方法的具体功能是由本地代码实现的,通常是用其他语言(如C或C++)编写的。
@Overridepublic void run() {if (target != null) {target.run();}}
这段代码的作用是执行一个线程的任务,该任务是通过 target 变量传递进来的。这里假设类中有一个名为 target 的变量,其类型是实现了 Runnable 接口的类的实例。Runnable 接口只有一个方法 run(),因此在这个上下文中,target.run() 就是调用了传递进来的任务的 run() 方法。
这段代码的逻辑很简单:
如果 target 不为 null,则表示有一个任务需要执行。调用 target.run() 来执行任务的实际逻辑。
这样,当一个实现了 Runnable 接口的对象被传递给这段代码所在的对象,它的 run() 方法就会被调用,从而执行该线程的任务。这在多线程编程中常常用于将任务与线程分离,实现更好的任务管理和代码结构。
private void exit() {if (group != null) {// 检查线程所属的线程组是否为非空。如果线程属于一个线程组,下面的代码将在该线程组上执行某些操作。 // 调用线程组的 threadTerminated 方法,传递当前线程实例作为参数。这可能是在线程终止时,通知线程组的某个方法。group.threadTerminated(this); // 将线程的 group 成员变量设置为 null,这样线程不再属于任何线程组。group = null;}// 将线程的 target 成员变量设置为 null,这表示线程不再持有一个任务对象。target = null;// 将与线程相关的一些状态和资源引用设置为 null,这将协助垃圾回收清理线程使用的资源,从而释放内存。threadLocals = null;inheritableThreadLocals = null;inheritedAccessControlContext = null;blocker = null;uncaughtExceptionHandler = null;}
总之,这段代码在线程退出时进行一系列资源清理操作,以确保线程和线程组之间的关联关系被解除,从而帮助系统释放资源并回收内存。这对于避免资源泄漏和确保程序正常终止非常重要。
@Deprecatedpublic final void stop() {
@Deprecated 注解用于标识一个方法、类或字段已被废弃,不再推荐使用。在这个上下文中,stop() 方法已被标记为废弃,意味着不建议继续使用该方法。
在过去,stop() 方法用于强制终止一个线程,但这种做法已被认为是不安全的,因为它可能导致线程在不可预测的状态下终止,从而导致资源泄漏或数据不一致。因此,Java 现在建议使用更加安全的方式来管理线程的终止,例如使用协作式的方式,通过标志位或其他线程间的通信来终止线程。
使用 @Deprecated 注解标记方法是为了告知开发者该方法不再是推荐的选择,并且可能在未来的版本中被移除。当开发者在使用被标记为废弃的方法时,编译器或开发环境通常会发出警告,以提醒开发者使用更合适的替代方法。
@Deprecatedpublic final synchronized void stop(Throwable obj) {
这个 stop(Throwable obj) 方法接受一个 Throwable 对象作为参数。它在过去被用于在强制终止线程时传递一个异常对象,但与之前相同,这种做法被认为是不安全的,可能导致线程和资源管理的问题。
public void interrupt() {// 这段代码首先检查当前线程是否正在调用自己的 interrupt() 方法,如果不是,则通过 checkAccess() 方法检查是否有权限进行操作。这是为了确保只有线程本身或具有适当权限的代码可以中断线程。if (this != Thread.currentThread())checkAccess();// 这是一个同步块,锁定了 blockerLock 对象。blockerLock 用于标识线程是否处于阻塞状态。阻塞状态的线程通常被阻止响应中断,因此需要特殊处理。synchronized (blockerLock) {// 尝试获取线程的 blocker 对象,如果存在的话。blocker 是一个用于表示线程是否被阻塞的接口。Interruptible b = blocker;if (b != null) {// 如果线程处于阻塞状态,即有一个 blocker 对象,以下操作会执行: // 调用底层方法来设置中断标志,但并不会真正中断线程。interrupt0(); // Just to set the interrupt flag // 通过 blocker 对象的 interrupt() 方法来中断线程,可能会取消阻塞状态。b.interrupt(this);return;}}// 如果线程不处于阻塞状态,直接调用底层方法来设置中断标志。interrupt0();}
总的来说,interrupt() 方法用于向线程发送中断信号。如果线程被阻塞(比如在 Object.wait() 或 Thread.sleep() 中),它会取消阻塞状态,并且可以通过 InterruptedException 来捕获中断信号。如果线程没有被阻塞,中断标志会被设置,线程可以在适当的时候检查这个标志来自行终止运行。这种方式可以更安全地处理线程的终止,而不是直接强制终止线程的运行。
public static boolean interrupted() {return currentThread().isInterrupted(true);}
currentThread():
这是一个静态方法,返回当前正在执行的线程的引用。
isInterrupted(true):
这是 Thread 类的实例方法,用于检查线程是否被中断,并且会清除中断标志。在这个上下文中,true 参数表示清除中断标志。
所以,这个 interrupted() 方法的作用是检查当前线程是否被中断,然后清除中断标志,以便后续的操作不会再受到中断的影响。通常,你会在代码中的某个地方使用 interrupted() 方法来判断线程是否被中断,然后采取适当的处理措施。
public boolean isInterrupted() {return isInterrupted(false);}
这段代码调用了另一个 isInterrupted(boolean) 方法,传递了 false 参数。这个 isInterrupted(boolean) 方法是 Thread 类的实例方法,用于检查线程是否被中断,并可以选择是否清除中断标志。
所以,这个 isInterrupted() 方法的作用是检查当前线程是否被中断,但不会清除中断标志。如果线程被中断,返回 true,否则返回 false。
private native boolean isInterrupted(boolean ClearInterrupted);
native 关键字:
这表示该方法的实现不在 Java 代码中,而是在本地代码中,通常是使用其他编程语言(如 C 或 C++)编写的。
boolean ClearInterrupted:
这是一个参数,用于指示是否清除中断标志。如果参数为 true,则方法会清除中断标志,如果参数为 false,则不会清除中断标志。
这段代码表示这个本地方法可以被用来检查线程是否被中断,并且可以选择是否清除中断标志。具体的实现在本地代码中,可能涉及到与底层操作系统或硬件的交互。这种方式通常用于直接操作底层资源或执行特定于平台的操作,而不是使用 Java 的标准库来实现。
@Deprecatedpublic void destroy() {
destroy() 方法在过去可能被用于销毁一个线程,但由于它可能引发不稳定的状态和资源泄漏,这种做法已经被认为是不安全的,并且在现代 Java 编程中不再推荐使用。
public final native boolean isAlive();
用于检查线程是否还活着(即线程是否处于活动状态)。这个方法被标记为 final 和 native,意味着它是不能被子类重写的,并且其具体实现在本地代码中。
public:表示这个方法是公共可访问的。final:表示这个方法是被标记为最终的,不允许子类对其进行重写。native:表示这个方法的具体实现不在 Java 代码中,而是在本地代码中,通常是使用其他编程语言(如 C 或 C++)编写的。boolean:表示这个方法返回一个布尔值。
这个方法的作用很简单:它用于检查当前线程是否仍处于活动状态,即线程是否还在运行中。如果线程正在执行或处于就绪状态,isAlive() 方法会返回 true;如果线程已经终止或未启动,它会返回 false。
通常情况下,可以在代码中使用 isAlive() 方法来检查线程是否仍在活动中,以便做出相应的处理。
@Deprecatedpublic final void suspend() {
suspend() 方法在过去可能被用于挂起线程的执行,暂停线程的运行,以及在稍后再次恢复线程的执行。然而,这种做法已被认为是不安全的,因为它可能导致线程在不可预测的状态下暂停,从而引发死锁或资源泄漏等问题。
@Deprecatedpublic final void resume() {
在过去,resume() 方法可能被用于从挂起状态恢复线程的执行。然而,类似于 suspend() 方法,resume() 方法同样被认为是不安全的,因为它可能导致线程在不可预测的状态下继续执行,从而引发并发问题或数据不一致。
public final void setPriority(int newPriority) {// 创建一个名为 g 的 ThreadGroup 对象引用。ThreadGroup g;// 检查当前线程是否有权限修改此线程的优先级。如果没有权限,会抛出一个 SecurityException 异常。checkAccess();// 检查新的优先级是否在有效的范围内。Java 线程的优先级范围是从 Thread.MIN_PRIORITY 到 Thread.MAX_PRIORITY。if (newPriority > MAX_PRIORITY || newPriority g.getMaxPriority()) {newPriority = g.getMaxPriority();}// 调用 setPriority0() 方法来设置线程的优先级,同时将线程的 priority 成员变量更新为新的优先级。setPriority0(priority = newPriority);}}
总之,这个方法允许设置线程的优先级,并且会根据线程所属的线程组的优先级限制来进行调整。然而,需要注意的是,在实际多线程编程中,使用优先级来控制线程的执行往往是不够可靠和预测的,因为线程优先级的实际影响因平台和实现而异。
public final int getPriority() {return priority;}
用于获取线程的优先级.
public final synchronized void setName(String name) {// 检查当前线程是否有权限修改此线程的名称。如果没有权限,会抛出一个 SecurityException 异常。checkAccess();if (name == null) {// 检查要设置的名称是否为 null。如果名称为 null,会抛出一个 NullPointerException 异常,说明名称不能为 null。throw new NullPointerException("name cannot be null");}// 将线程的名称设置为传入的名称。this.name = name;// 检查线程的状态是否为非零。这可能是用于检查线程是否已经启动。如果线程已经启动,以下操作会执行。if (threadStatus != 0) {// 调用 setNativeName() 方法来设置本地线程的名称。这通常会涉及底层操作系统或平台相关的操作。setNativeName(name);}}
总之,这个方法用于设置线程的名称。线程名称是一个用于标识线程的可选字符串,对于调试和日志记录非常有用。需要注意的是,设置线程名称不会影响线程的行为,它只是一个用于标识线程的描述性信息。
public final String getName() {return name;}
用于获取线程的名称。
public final ThreadGroup getThreadGroup() {return group;}
一个线程可以通过构造函数显式地指定所属的线程组,如果没有指定,则线程将会被放置在其父线程的线程组中。如果线程在没有被明确分配线程组的情况下运行,那么 getThreadGroup() 方法将返回 null。
public static int activeCount() {return currentThread().getThreadGroup().activeCount();}
这个方法执行以下步骤:
currentThread():获取当前正在执行的线程的引用。getThreadGroup():从当前线程获取其所属的线程组。activeCount():调用线程组的 activeCount() 方法,返回当前线程组中活动线程的数量。
因此,activeCount() 方法的作用是获取当前线程组中活动线程的数量。这可以用于监视线程的活动情况。需要注意的是,活动线程的数量是动态变化的,可能会随着线程的创建和终止而变化。
public static int enumerate(Thread tarray[]) {return currentThread().getThreadGroup().enumerate(tarray);}
这个方法执行以下步骤:
currentThread():获取当前正在执行的线程的引用。getThreadGroup():从当前线程获取其所属的线程组。enumerate(tarray):调用线程组的 enumerate() 方法,将线程组中的活动线程复制到指定的线程数组 tarray 中,并返回实际复制的线程数。
因此,enumerate(Thread tarray[]) 方法的作用是将当前线程组中的活动线程复制到指定的线程数组中,以便进行监视或其他操作。这个方法可以帮助你获取线程组中的活动线程信息。需要注意的是,复制的线程数可能小于传入的数组的大小,因为线程组中的线程数量可能会动态变化。
@Deprecatedpublic native int countStackFrames();
@Deprecated 注解:用于标记方法已被废弃,不再推荐使用。public:表示这个方法是公共可访问的。native:表示这个方法的实现是在本地代码中而不是 Java 代码中。int:表示这个方法返回一个整数值。
这个方法的目的是计算调用堆栈中的帧(方法调用)数量。在过去,这个方法可能被用于检查调用堆栈的深度。然而,由于不同的 Java 虚拟机和操作系统可能会有不同的实现和行为,因此这个方法在实际应用中可能不太可靠。
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;}}}
这个方法的作用是等待调用线程执行完毕,或者在给定的超时时间内等待线程执行完毕。它可以被用于控制线程的协同执行,例如等待某个线程完成后再继续执行其他操作。
方法的具体实现如下:
获取当前时间作为基准时间 base。进入一个循环,直到调用线程执行完毕或达到超时时间。如果传入的 millis 参数小于 0,抛出一个 IllegalArgumentException 异常,表示超时值不能为负数。如果 millis 参数为 0,进入一个循环,当线程还活着时,等待时间为0毫秒,即无限等待,直到线程终止。如果 millis 参数大于 0,进入一个循环,计算当前时间到基准时间的时间差 now,计算还需要等待的时间 delay,然后等待 delay 毫秒。在每次循环迭代中,重新计算 now 的值,以便实时更新等待时间。
需要注意的是,join() 方法可能会抛出 InterruptedException 异常,表示在等待过程中,线程被中断。这种方法的使用可以使得线程之间协同执行,等待某个线程的完成,然后继续执行其他操作。
public final synchronized void join(long millis, int nanos)throws InterruptedException {if (millis < 0) {throw new IllegalArgumentException("timeout value is negative");}if (nanos 999999) {throw new IllegalArgumentException("nanosecond timeout value out of range");}if (nanos >= 500000 || (nanos != 0 && millis == 0)) {millis++;}join(millis);}
这个方法的作用和之前介绍的 join(long millis) 方法类似,但是增加了对纳秒级别的超时时间的支持。
方法的具体实现如下:
检查传入的 millis 参数是否为负数,如果是,抛出一个 IllegalArgumentException 异常,表示超时值不能为负数。检查传入的 nanos 参数是否在合法范围内(0 到 999999),如果不在范围内,抛出一个 IllegalArgumentException 异常,表示纳秒超时值超出范围。如果 nanos 大于等于 500000 或者 nanos 不为0且 millis 为0,则将 millis 值加1。这是因为 join() 方法的超时精度是毫秒级别,所以在这种情况下会额外等待一毫秒。最后,调用了 join(millis) 方法,以毫秒级别的超时值来等待线程执行完毕。
这个方法允许在等待的时候同时指定纳秒级别的超时时间,可以更精细地控制线程的等待。需要注意的是,join() 方法可能会抛出 InterruptedException 异常,表示在等待过程中,线程被中断。
public final void join() throws InterruptedException {join(0);}
这个方法的作用是等待调用线程执行完毕,不设置超时时间,即无限等待。
方法的具体实现很简单:
调用了 join(0) 方法,传入超时时间为0,即表示无限等待。
这个方法允许在不设置超时时间的情况下等待线程执行完毕。需要注意的是,join() 方法可能会抛出 InterruptedException 异常,表示在等待过程中,线程被中断。
public static void dumpStack() {new Exception("Stack trace").printStackTrace();}
这个方法的作用是打印当前线程的调用堆栈信息,通常用于调试和诊断。它的实现如下:
创建一个新的 Exception 对象,传入 "Stack trace" 作为异常的消息。调用 printStackTrace() 方法,将调用堆栈信息打印到标准错误流中。
通过调用这个方法,可以在程序中的某个位置主动输出调用堆栈信息,以方便找到代码执行过程中的问题。需要注意的是,这种方法会在标准错误流中产生输出,因此在生产环境中可能需要小心使用,以避免泄露敏感信息。
public final void setDaemon(boolean on) {checkAccess();if (isAlive()) {throw new IllegalThreadStateException();}daemon = on;}
这个方法的作用是设置当前线程是否为守护线程。守护线程是一种在后台运行的线程,它的存在不会阻止程序的终止。当所有的非守护线程都终止时,守护线程会随着 JVM 的关闭而终止。
方法的具体实现如下:
checkAccess();:检查当前线程是否有权限修改此线程的属性。如果没有权限,会抛出一个 SecurityException 异常。if (isAlive()) { ... }:检查当前线程是否处于活动状态(已启动但尚未终止)。如果线程已经启动,抛出一个 IllegalThreadStateException 异常,表示不能修改已经启动的线程的属性。(所以要在启动之前设置)daemon = on;:根据传入的布尔值 on,设置线程是否为守护线程。
需要注意的是,守护线程通常用于执行后台任务,例如垃圾回收、日志记录等。在某些情况下,当所有的非守护线程终止时,守护线程可能会被强制终止,因此它们不能用于执行必须完整执行的任务。
public final boolean isDaemon() {return daemon;}
用于检查线程是否为守护线程。
public final void checkAccess() {SecurityManager security = System.getSecurityManager();if (security != null) {security.checkAccess(this);}}
这个方法的作用是检查当前线程是否有权限修改此线程的属性。在 Java 中,可以通过安全管理器(SecurityManager)来控制程序的安全行为,包括对线程的访问权限进行控制。
方法的具体实现如下:
System.getSecurityManager():获取当前运行时的安全管理器(如果已经设置)。if (security != null) { ... }:如果存在安全管理器。security.checkAccess(this);:调用安全管理器的 checkAccess(Thread t) 方法,传入当前线程作为参数。这个方法用于检查当前线程是否有权限修改指定线程的属性。如果没有权限,会抛出一个 SecurityException 异常。
这个方法的使用可以帮助确保线程的属性被正确地管理和控制,以遵循程序的安全策略。需要注意的是,默认情况下,大多数应用程序不会使用安全管理器,因此这个方法可能不会实际执行任何操作。
public String toString() {ThreadGroup group = getThreadGroup();if (group != null) {return "Thread[" + getName() + "," + getPriority() + "," + group.getName() + "]";} else {return "Thread[" + getName() + "," + getPriority() + "," +"" + "]";}}
这个方法的作用是生成一个描述当前线程的字符串。具体的生成方式如下:
ThreadGroup group = getThreadGroup();:获取当前线程所属的线程组。if (group != null) { ... } else { ... }:如果线程所属的线程组不为空,执行下面的操作,否则执行 else 块中的操作。"Thread[" + getName() + "," + getPriority() + "," + group.getName() + "]":生成一个包含线程名称、线程优先级和线程组名称的字符串,表示当前线程的信息。"Thread[" + getName() + "," + getPriority() + "," + "" + "]":如果线程所属的线程组为空,生成一个包含线程名称和线程优先级的字符串,表示当前线程的信息。
这个方法的目的是生成一个描述性的字符串,用于标识线程的信息,例如名称、优先级和线程组。
@CallerSensitivepublic ClassLoader getContextClassLoader() {if (contextClassLoader == null)return null;SecurityManager sm = System.getSecurityManager();if (sm != null) {ClassLoader.checkClassLoaderPermission(contextClassLoader, Reflection.getCallerClass());}return contextClassLoader;}
这个方法的作用是获取当前线程的上下文类加载器。上下文类加载器是一个类加载器,由线程的创建者设置,用于加载线程中运行的代码所需的类。
方法的具体实现如下:
if (contextClassLoader == null) return null;:如果上下文类加载器为 null,直接返回 null,表示没有设置上下文类加载器。SecurityManager sm = System.getSecurityManager();:获取当前运行时的安全管理器。if (sm != null) { ... }:如果存在安全管理器。ClassLoader.checkClassLoaderPermission(contextClassLoader, Reflection.getCallerClass());:调用 ClassLoader 类的静态方法 checkClassLoaderPermission(),检查当前线程是否有权限获取上下文类加载器。这个方法的调用会检查安全策略是否允许获取类加载器的权限。return contextClassLoader;:返回上下文类加载器。
需要注意的是,上下文类加载器在一些特定的上下文中非常有用,例如在应用服务器中,用于加载不同的应用程序的类。然而,在大多数情况下,Java 类加载器的层次结构已经能够满足大部分的类加载需求,上下文类加载器的使用应该谨慎,避免引入不必要的复杂性。
public void setContextClassLoader(ClassLoader cl) {SecurityManager sm = System.getSecurityManager();if (sm != null) {sm.checkPermission(new RuntimePermission("setContextClassLoader"));}contextClassLoader = cl;}
这个方法的作用是设置当前线程的上下文类加载器。上下文类加载器是一个类加载器,用于加载线程中运行的代码所需的类。
方法的具体实现如下:
SecurityManager sm = System.getSecurityManager();:获取当前运行时的安全管理器。if (sm != null) { ... }:如果存在安全管理器。sm.checkPermission(new RuntimePermission("setContextClassLoader"));:调用安全管理器的 checkPermission() 方法,检查是否有权限设置上下文类加载器。这个方法的调用会检查安全策略是否允许设置上下文类加载器的权限。通常,这需要有 RuntimePermission("setContextClassLoader") 权限。contextClassLoader = cl;:将传入的类加载器 cl 设置为当前线程的上下文类加载器。
public static native boolean holdsLock(Object obj);
这个方法的作用是判断当前线程是否持有指定对象 obj 的监视器锁。监视器锁也称为内置锁或对象锁,用于在多线程环境中实现对对象的同步控制。
方法的具体实现是本地方法,由底层的 JVM 提供实现。这个方法通常用于调试和诊断,以判断当前线程是否在特定对象上持有锁,以避免死锁或其他同步问题。
需要注意的是,这个方法只能判断当前线程是否持有指定对象的监视器锁,不能判断其他线程是否持有锁。如果你需要更全面地了解锁的状态,可能需要借助其他工具和技术来进行监视和分析。
public StackTraceElement[] getStackTrace() {if (this != Thread.currentThread()) {// check for getStackTrace permissionSecurityManager security = System.getSecurityManager();if (security != null) {security.checkPermission(SecurityConstants.GET_STACK_TRACE_PERMISSION);}// optimization so we do not call into the vm for threads that// have not yet started or have terminatedif (!isAlive()) {return EMPTY_STACK_TRACE;}StackTraceElement[][] stackTraceArray = dumpThreads(new Thread[] {this});StackTraceElement[] stackTrace = stackTraceArray[0];// a thread that was alive during the previous isAlive call may have// since terminated, therefore not having a stacktrace.if (stackTrace == null) {stackTrace = EMPTY_STACK_TRACE;}return stackTrace;} else {// Don't need JVM help for current threadreturn (new Exception()).getStackTrace();}}
这个方法的作用是获取当前线程的调用堆栈信息,以查看调用方法和位置。方法的实现涉及了一些安全性检查和优化:
if (this != Thread.currentThread()) { ... }:检查当前线程是否是调用线程本身。如果不是,进行一系列的操作来获取堆栈信息。SecurityManager 部分:如果存在安全管理器,检查是否有权限获取堆栈信息。这是为了确保只有受信任的代码可以获取堆栈信息。if (!isAlive()) { ... }:检查当前线程是否是活动状态(已启动但尚未终止)。如果线程未启动或已终止,直接返回一个空的堆栈轨迹数组。调用 dumpThreads(new Thread[] {this}) 获取当前线程的调用堆栈信息。dumpThreads 方法通常是一个本地方法,用于获取线程的堆栈信息。处理可能为空的堆栈信息:如果堆栈信息为空,返回一个空的堆栈轨迹数组。返回获取到的堆栈信息。else 部分:如果当前线程是调用线程本身,直接通过创建一个 Exception 实例来获取堆栈信息。这是因为当前线程的堆栈信息是比较容易获取的。
这个方法在调试和诊断时非常有用,可以用于追踪代码的执行路径。需要注意的是,获取堆栈信息可能会涉及一些性能开销,因此在生产代码中需要谨慎使用。
public static Map getAllStackTraces() {// check for getStackTrace permissionSecurityManager security = System.getSecurityManager();if (security != null) {security.checkPermission(SecurityConstants.GET_STACK_TRACE_PERMISSION);security.checkPermission(SecurityConstants.MODIFY_THREADGROUP_PERMISSION);}// Get a snapshot of the list of all threadsThread[] threads = getThreads();StackTraceElement[][] traces = dumpThreads(threads);Map m = new HashMap(threads.length);for (int i = 0; i < threads.length; i++) {StackTraceElement[] stackTrace = traces[i];if (stackTrace != null) {m.put(threads[i], stackTrace);}// else terminated so we don't put it in the map}return m;}
这个方法的作用是获取所有活动线程的调用堆栈信息,以查看每个线程的调用方法和位置。方法的实现涉及了一些安全性检查和操作:
SecurityManager 部分:如果存在安全管理器,检查是否有权限获取堆栈信息和修改线程组。这是为了确保只有受信任的代码可以获取线程的堆栈信息。Thread[] threads = getThreads();:获取当前所有活动线程的数组。StackTraceElement[][] traces = dumpThreads(threads);:调用 dumpThreads(threads) 方法,获取所有活动线程的堆栈信息。创建一个 HashMap 对象 m,用于存储每个线程及其对应的堆栈信息。遍历所有活动线程,将线程及其堆栈信息添加到 m 中。返回包含所有活动线程及其堆栈信息的 Map 对象。
这个方法在调试、监视和诊断时非常有用,可以用于分析多线程程序的执行路径和状态。需要注意的是,获取所有线程的堆栈信息可能会涉及一些性能开销,因此在生产代码中需要谨慎使用。
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();}
这个方法的作用是判断指定的类是否覆盖了上下文类加载器。上下文类加载器在多线程环境中用于加载线程中运行的代码所需的类。
方法的实现如下:
if (cl == Thread.class) return false;:如果指定的类是 Thread.class,表示线程类本身,直接返回 false,因为线程类不会覆盖上下文类加载器。processQueue(Caches.subclassAuditsQueue, Caches.subclassAudits);:调用 processQueue 方法,用于处理类的子类审计队列。WeakClassKey key = new WeakClassKey(cl, Caches.subclassAuditsQueue);:使用指定的类和子类审计队列创建一个 WeakClassKey 对象,用于在缓存中存储类的覆盖信息。Boolean result = Caches.subclassAudits.get(key);:从缓存中获取指定类的覆盖信息。if (result == null) { ... }:如果在缓存中找不到指定类的覆盖信息。result = Boolean.valueOf(auditSubclass(cl));:调用 auditSubclass(cl) 方法,判断指定类是否覆盖了上下文类加载器,并将结果包装成 Boolean 对象。Caches.subclassAudits.putIfAbsent(key, result);:将计算得到的覆盖信息放入缓存中。return result.booleanValue();:返回指定类是否覆盖了上下文类加载器的布尔值。
这个方法在一些特定的场景下可能会用于确定类是否会覆盖上下文类加载器,以便做出相应的处理。
private static boolean auditSubclass(final Class subcl) {Boolean result = AccessController.doPrivileged(new PrivilegedAction() {public Boolean run() {for (Class cl = subcl; cl != Thread.class; cl = cl.getSuperclass()){try {cl.getDeclaredMethod("getContextClassLoader", new Class[0]);return Boolean.TRUE;} catch (NoSuchMethodException ex) {}try {Class[] params = {ClassLoader.class};cl.getDeclaredMethod("setContextClassLoader", params);return Boolean.TRUE;} catch (NoSuchMethodException ex) {}}return Boolean.FALSE;}});return result.booleanValue();}
这个方法的作用是检查给定的类是否覆盖了上下文类加载器的相关方法,即 getContextClassLoader() 和 setContextClassLoader(ClassLoader)。上下文类加载器在多线程环境中用于加载线程中运行的代码所需的类。
方法的实现如下:
使用 AccessController.doPrivileged(...) 调用,该调用允许在特权访问的上下文中执行指定的代码块。在代码块中,从给定的类 subcl 开始迭代,检查是否存在 getContextClassLoader() 或 setContextClassLoader(ClassLoader) 方法。针对每个类 cl,尝试获取 getContextClassLoader() 方法,如果存在,返回 Boolean.TRUE。如果不存在 getContextClassLoader() 方法,尝试获取 setContextClassLoader(ClassLoader) 方法,如果存在,返回 Boolean.TRUE。如果都不存在,表示该类及其超类都没有覆盖上下文类加载器的相关方法,返回 Boolean.FALSE。返回特权代码块中计算得到的结果,即 Boolean.TRUE 或 Boolean.FALSE。
这个方法在一些特定的场景下可能会用于确定类是否会覆盖上下文类加载器的相关方法,以便做出相应的处理。需要注意的是,这里使用了特权访问来执行敏感的反射操作,以确保只有受信任的代码能够执行这些操作。
private native static StackTraceElement[][] dumpThreads(Thread[] threads);
这个方法的作用是获取一组线程的调用堆栈信息。由于线程的堆栈信息通常需要访问底层的线程状态和执行堆栈信息,因此这个方法是一个本地方法,会在底层的 JVM 实现中实际执行。
该方法的签名表明它接受一个 Thread[] 数组作为参数,表示要获取堆栈信息的线程。返回的结果是一个二维数组 StackTraceElement[][],其中每个子数组对应一个线程的调用堆栈信息。每个子数组中的元素 StackTraceElement 表示调用堆栈的一个元素,包含类名、方法名和行号等信息。
private native static Thread[] getThreads();
这个方法的作用是获取当前所有活动线程的数组。由于线程的状态和信息通常需要访问底层的线程管理数据结构,因此这个方法是一个本地方法,会在底层的 JVM 实现中实际执行。
该方法返回一个 Thread[] 数组,其中包含了当前所有活动线程的引用。通过这个方法,可以获取活动线程的列表,以便进行调试、诊断和监控。
public long getId() {return tid;}
这个方法的作用是获取当前线程的唯一标识符(Thread ID)。每个线程在 JVM 内部都有一个唯一的标识符,用于在操作系统和 JVM 内部进行区分。
在这里,tid 变量代表线程的唯一标识符,它很可能是在线程对象创建时由 JVM 分配的。通过调用这个方法,可以获取当前线程的标识符,以便在特定的情况下进行标识或区分。
需要注意的是,线程的标识符是一个较低级别的概念,在 Java 中通常使用更高级别的方式来操作和管理线程。这个方法在一些特定的情况下可能会用于了解线程的标识符,但在一般情况下,不需要直接操作线程的标识符。
public State getState() {// get current thread statereturn sun.misc.VM.toThreadState(threadStatus);}
这个方法的作用是获取当前线程的状态。在 Java 中,线程可以处于不同的状态,如新建、就绪、运行、阻塞、等待、终止等。这个方法通过获取线程的 threadStatus 属性来确定线程的状态,并将其转换为对应的 State 枚举类型。
在这里,sun.misc.VM.toThreadState(threadStatus) 表示将底层的线程状态码(存储在 threadStatus 变量中)映射到 Java 的 Thread.State 枚举类型。
通过调用这个方法,可以获取当前线程的状态,以便在特定的情况下了解线程的状态,进行调试、监控或诊断。需要注意的是,线程状态是动态变化的,可能在不同的时间点处于不同的状态。
public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler eh) {SecurityManager sm = System.getSecurityManager();if (sm != null) {sm.checkPermission(new RuntimePermission("setDefaultUncaughtExceptionHandler"));} defaultUncaughtExceptionHandler = eh; }
这个方法的作用是设置默认的未捕获异常处理程序(Uncaught Exception Handler)。未捕获异常是指在线程中未被捕获的异常,如果未被处理,可能会导致程序终止。为了捕获并处理这些未捕获的异常,可以设置一个自定义的异常处理程序。
方法的实现如下:
SecurityManager 部分:如果存在安全管理器,检查是否有权限设置默认的未捕获异常处理程序。这是为了确保只有受信任的代码可以设置异常处理程序。defaultUncaughtExceptionHandler = eh;:将传入的 UncaughtExceptionHandler 对象 eh 设置为默认的未捕获异常处理程序。
通过调用这个方法,可以为整个应用程序设置一个默认的未捕获异常处理程序,以便在发生未捕获异常时进行统一的处理。默认的未捕获异常处理程序可以捕获并记录异常信息,从而帮助进行调试和监控。
public static UncaughtExceptionHandler getDefaultUncaughtExceptionHandler(){return defaultUncaughtExceptionHandler;}
这个方法的作用是获取默认的未捕获异常处理程序(Uncaught Exception Handler)。默认的未捕获异常处理程序是一个可以设置的全局异常处理程序,用于捕获和处理线程中未被捕获的异常。
通过调用这个方法,可以获取当前应用程序设置的默认的未捕获异常处理程序。这对于了解异常处理策略、调试、监控以及日志记录等方面非常有用。需要注意的是,如果默认的未捕获异常处理程序未被设置,这个方法将返回 null。
public UncaughtExceptionHandler getUncaughtExceptionHandler() {return uncaughtExceptionHandler != null ?uncaughtExceptionHandler : group;}
这个方法的作用是获取当前线程的未捕获异常处理程序(Uncaught Exception Handler)。线程中的未捕获异常是指在线程内部抛出的异常,但没有被捕获和处理,可能会导致程序的终止。
方法的实现如下:
return uncaughtExceptionHandler != null ? uncaughtExceptionHandler : group;:首先,判断线程自身是否有设置未捕获异常处理程序(uncaughtExceptionHandler)。如果有,返回该处理程序;如果没有,返回线程所在的线程组的未捕获异常处理程序(group)。
通过调用这个方法,可以获取当前线程的未捕获异常处理程序,以便在发生未捕获异常时进行相应的处理。如果线程自身没有设置处理程序,就会返回线程组的处理程序,这可以实现一种层次化的异常处理策略。
public void setUncaughtExceptionHandler(UncaughtExceptionHandler eh) {checkAccess();uncaughtExceptionHandler = eh;}
这个方法的作用是设置当前线程的未捕获异常处理程序(Uncaught Exception Handler)。未捕获异常是指在线程内部抛出的异常,但没有被捕获和处理,可能会导致程序的终止。
方法的实现如下:
checkAccess();:首先,调用 checkAccess() 方法,检查当前线程是否有权限修改未捕获异常处理程序。这是为了确保只有受信任的代码可以设置异常处理程序。uncaughtExceptionHandler = eh;:将传入的 UncaughtExceptionHandler 对象 eh 设置为当前线程的未捕获异常处理程序。
通过调用这个方法,可以为当前线程设置一个自定义的未捕获异常处理程序,以便在发生未捕获异常时进行处理。这可以用于实现自定义的异常处理逻辑,如记录日志、发送警报等。需要注意的是,线程的未捕获异常处理程序只对该线程内的未捕获异常有效。
private void dispatchUncaughtException(Throwable e) {getUncaughtExceptionHandler().uncaughtException(this, e);}
这个方法的作用是将未捕获的异常分发给线程的未捕获异常处理程序(Uncaught Exception Handler)。未捕获异常是指在线程内部抛出的异常,但没有被捕获和处理,可能会导致程序的终止。
方法的实现如下:
getUncaughtExceptionHandler():调用 getUncaughtExceptionHandler() 方法,获取当前线程的未捕获异常处理程序。.uncaughtException(this, e);:调用获取到的未捕获异常处理程序的 uncaughtException(Thread t, Throwable e) 方法,将当前线程(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);}}
这个方法的作用是处理一个引用队列中的引用。引用队列是用于管理弱引用、软引用等引用类型的队列,在对象被垃圾回收器回收时,相关的引用会被放入这个队列中。
方法的实现如下:
queue:传入一个引用队列 ReferenceQueue<Class>,表示要处理的引用队列。map:传入一个并发映射(ConcurrentMap)对象,它的键类型是某种弱引用(WeakReference)的子类,值类型可以是任意类型。这个映射用于存储与引用相关联的数据。while((ref = queue.poll()) != null):使用循环从引用队列中取出一个引用。queue.poll() 方法从队列中获取一个引用,如果队列为空,返回 null。map.remove(ref):通过获取的引用 ref,在映射 map 中移除与该引用相关联的数据。这通常是为了清理不再需要的数据。
通过调用这个方法,可以周期性地处理引用队列中的引用,清理不再需要的数据,以便释放资源。这在处理弱引用、软引用等场景下是常见的模式。
private native void setPriority0(int newPriority);
这个方法的作用是在底层操作系统级别设置线程的优先级。线程的优先级决定了线程在竞争 CPU 时间时的调度顺序。较高优先级的线程可能会在较低优先级的线程之前执行。
由于线程的优先级是依赖于底层操作系统的,因此这个方法是一个本地方法,会在底层的 JVM 实现中实际执行。
在这里,newPriority 是要设置的新优先级值,通常是一个整数。通过调用这个方法,可以更改线程的优先级,从而影响线程的调度行为。需要注意的是,不同操作系统和 JVM 实现可能会对线程优先级的具体影响有所不同。
private native void stop0(Object o);
在底层操作系统级别停止线程的执行
private native void suspend0();
用于暂停线程的执行
private native void resume0();
用于恢复被暂停的线程的执行
private native void interrupt0();
用于中断线程的等待状态
private native void setNativeName(String name);
用于设置线程的本地名称
总结
Thread 类是 Java 标准库中用于创建和管理线程的核心类之一。它提供了一系列方法和功能,用于创建、启动、管理和控制线程的行为。以下是对 Thread 类的一些关键特点和功能的总结:
线程的创建和启动:
通过继承 Thread 类并重写 run 方法,可以创建一个新的线程。调用 start 方法来启动线程,启动后会执行 run 方法中的代码。
线程状态:
Thread 类定义了多个枚举类型 State,表示线程可能的不同状态,如 NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING 和 TERMINATED。
线程优先级:
Thread 类允许为线程设置优先级,用于在多个线程竞争 CPU 时间时进行调度。优先级范围从 Thread.MIN_PRIORITY 到 Thread.MAX_PRIORITY。
线程同步和互斥:
Thread 类提供了 synchronized 关键字,用于实现线程之间的同步和互斥。此外,还有 wait、notify 和 notifyAll 方法用于线程的等待和唤醒操作。
线程中断:
通过 interrupt 方法,可以中断线程的等待状态,使其从等待中唤醒。线程需要在代码中适时检查中断状态并做出响应。
线程组:
Thread 类支持将线程组进行分组,方便管理和操作一组相关的线程。
异常处理:
Thread 类允许为线程设置未捕获异常的处理器(UncaughtExceptionHandler),以便在线程抛出未捕获异常时进行处理。
线程属性和管理:
Thread 类提供了许多方法来查询和设置线程的属性,如名称、状态、优先级等。Thread 类也支持获取活动线程数、列举活动线程等管理操作。
本地方法调用:
Thread 类中有一些本地方法,用于底层操作系统级别的线程管理,如设置优先级、中断线程等。然而,大多数情况下,不建议直接使用这些方法。
总之,Thread 类是 Java 多线程编程的核心之一,提供了丰富的功能来创建、管理和控制线程。然而,在使用这些功能时,需要谨慎考虑线程安全、资源管理等问题,以确保多线程程序的正确性和稳定性。