本想看看 AQS 相关代码,但是返现 Thread 状态与通信内容记不清楚,就先看下 Thread 类源码。
Thread 类的源码简单,因为主要逻辑都是 native 方法中。本文与其说是源码阅读,不如说是Java Doc 阅读。
构造函数
构造代码较简单,忽略,逻辑全部在 init 方法中。
/**
* Initializes a Thread.
*
* @param g the Thread group
* @param target the object whose run() method gets called
* @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();
}
/* If the security doesn't have a strong opinion of the matter
use the parent thread group. */
if (g == null) {
g = parent.getThreadGroup();
}
}
/* checkAccess regardless of whether or not threadgroup is
explicitly passed in. */
g.checkAccess();
/*
* Do we have the required permissions?
*/
if (security != null) {
if (isCCLOverridden(getClass())) {
security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
}
}
g.addUnstarted();
this.group = g;
// 新建子线程默认拥有和父线程相同的优先级和daemon属性
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 类的成员变量
private volatile String name; // 线程名称,可通过构造指定
private int priority; // Java 线程的优先级定义为从 1 到 10 的等级,默认为 5
private Thread threadQ; //
private long eetop; //
private boolean single_step; //
private boolean daemon = false; // 守护线程
private boolean stillborn = false;
private Runnable target; // Runnable 对象
private ThreadGroup group; // 线程组
private ClassLoader contextClassLoader;
private AccessControlContext inheritedAccessControlContext;
private static int threadInitNumber;
ThreadLocalMap threadLocals = null; // 线程本地变量Map, 由 ThreadLocal 持有
ThreadLocalMap inheritableThreadLocals = null; // 可继承的线程本地变量,由 InheritableThreadLocal 持有
private long stackSize; // 线程要求的栈深度,有些VM会忽略,暂不深究
private long nativeParkEventPointer;
private long tid; // 线程ID
private static long threadSeqNumber; // 用户生成线程ID,计数用
private volatile int threadStatus = 0; // 线程状态,下文由单独描述
volatile Object parkBlocker;
private volatile Interruptible blocker;
private final Object blockerLock = new Object();
public static final int MIN_PRIORITY = 1;
public static final int NORM_PRIORITY = 5;
public static final int MAX_PRIORITY = 10;
private static final StackTraceElement[] EMPTY_STACK_TRACE;
private static final RuntimePermission SUBCLASS_IMPLEMENTATION_PERMISSION;
private volatile Thread.UncaughtExceptionHandler uncaughtExceptionHandler;
private static volatile Thread.UncaughtExceptionHandler defaultUncaughtExceptionHandler;
@Contended("tlr")
long threadLocalRandomSeed;
@Contended("tlr")
int threadLocalRandomProbe;
@Contended("tlr")
int threadLocalRandomSecondarySeed;
线程状态, 注释异常详细,不再赘述。
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.
*/
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}.
*/
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}
*
*/
TIMED_WAITING,
/**
* Thread state for a terminated thread.
* The thread has completed execution.
*/
TERMINATED;
}
在介绍完 Thread 类的各个方法之后,再介绍线程状态转变的逻辑。
Thread 主要方法介绍
currentThread
public static native Thread currentThread(); // 获取当前线程
yield
public static native void yield(); // 暗示调度器让出当前线程的执行时间片,调度器可以选择忽略该暗示
sleep
public static native void sleep(long millis) 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);
}
interrupted
/**
* 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).
* 返回当前线程是否被打断(打断标志是否被置位),会清除中断标志,即第二次调用会返回 false
*
* 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
*/
public static boolean interrupted() {
return currentThread().isInterrupted(true);
}
dumpStack
/**
* Prints a stack trace of the current thread to the standard error stream.
* This method is used only for debugging.
* 打印当前执行线程的栈信息
*
* @see Throwable#printStackTrace()
*/
public static void dumpStack() {
new Exception("Stack trace").printStackTrace();
}
以上都是静态方法,正对当前正在运行线程的操作。
下面开始介绍成员方法,针对某一线程的操作。
clone
抛出异常
start
/**
* Causes this thread to begin execution; the Java Virtual Machine
* calls the run
method of this thread.
* 触发线程开始执行;JVM 调用该线程的 run 方法
*
* 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).
*
* 结果是同时有两个线程是 running 状态, 一个调用 start 方法返回, 一个执行线程的 run 方法
* 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()
*/
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".
*/
// 检查状态必须为 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 */
}
}
}
private native void start0();
run
// run 方法,就是运行 target 的 run 方法,不能当作新起一个线程
public void run() {
if (target != null) {
target.run();
}
}
stop
停止线程,方法已经被 @Deprecated 注释,不在详细介绍
interrupt
/**
* 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}.
* 如果这个线程阻塞在Object.wait(),Thread.join(),Thread.sleep()上,那么该线程会收到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}.
* 如果这个线程阻塞在InterruptibleChannel的IO操作上, 打断标志会被置位,并抛出 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.
* 如果这个线程阻塞在 Selector 上,打断标志会被置位,那么该Selector的selection操作将会立即返回一个非0的结果,
* 且Selector.wakeup()会被调用
*
*
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.
* 打断一个非活状态( isAlive 方法,返回 false)的线程,无任何影响
*
* @throws SecurityException
* if the current thread cannot modify this thread
*
* @revised 6.0
* @spec JSR-51
*/
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();
}
isInterrupted
/**
* 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.
* 返回线程是否被打断(打断标志是否被置位),传入的参数决定是否该方法是否会清除终端标志位
*/
private native boolean isInterrupted(boolean ClearInterrupted);
destroy
被 @Deprecated 修饰,抛出异常
isAlive
/**
* Tests if this thread is alive. A thread is alive if it has
* been started and has not yet died.
* 返回当前线程是否还活着,start()后且还没有死亡的线程均视为活着的线程
*
* @return true
if this thread is alive;
* false
otherwise.
*/
public final native boolean isAlive();
suspend、resume、countStackFrames
被 @Deprecated 修饰
setPriority getPriority
/**
* Changes the priority of this thread.
* 修改线程优先级
*
* First the checkAccess
method of this thread is called
* with no arguments. This may result in throwing a
* SecurityException
.
*
* Otherwise, the priority of this thread is set to the smaller of
* the specified newPriority
and the maximum permitted
* priority of the thread's thread group.
*
* @param newPriority priority to set this thread to
* @exception IllegalArgumentException If the priority is not in the
* range MIN_PRIORITY
to
* MAX_PRIORITY
.
* @exception SecurityException if the current thread cannot modify
* this thread.
* @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);
}
}
/**
* Returns this thread's priority.
* 返回线程优先级
*
* @return this thread's priority.
* @see #setPriority
*/
public final int getPriority() {
return priority;
}
setName、getName
/**
* Changes the name of this thread to be equal to the argument
* name
.
* 修改线程名称
*
* First the checkAccess
method of this thread is called
* with no arguments. This may result in throwing a
* SecurityException
.
*
* @param name the new name for this thread.
* @exception SecurityException if the current thread cannot modify this
* thread.
* @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);
}
}
/**
* Returns this thread's name.
* 获取线程名称
*
* @return this thread's name.
* @see #setName(String)
*/
public final String getName() {
return name;
}
getThreadGroup
/**
* Returns the thread group to which this thread belongs.
* This method returns null if this thread has died
* (been stopped).
* 返回所属线程组,如果该线程已死,返回null
*
* @return this thread's thread group.
*/
public final ThreadGroup getThreadGroup() {
return group;
}
/**
* Returns an estimate of the number of active threads in the current
* thread's {@linkplain java.lang.ThreadGroup thread group} and its
* subgroups. Recursively iterates over all subgroups in the current
* thread's thread group.
* 返回当前线程所属的线程组及其子线程组的估算的活跃线程数目
*
* The value returned is only an estimate because the number of
* threads may change dynamically while this method traverses internal
* data structures, and might be affected by the presence of certain
* system threads. This method is intended primarily for debugging
* and monitoring purposes.
* 返回值是估算的,因为在该方法执行时,活跃线程是在动态变化的
*
* @return an estimate of the number of active threads in the current
* thread's thread group and in any other thread group that
* has the current thread's thread group as an ancestor
*/
public static int activeCount() {
return currentThread().getThreadGroup().activeCount();
}
/**
* Copies into the specified array every active thread in the current
* thread's thread group and its subgroups. This method simply
* invokes the {@link java.lang.ThreadGroup#enumerate(Thread[])}
* method of the current thread's thread group.
* 复制当前线程组及其子线程组的活跃线程到数组中
*
* An application might use the {@linkplain #activeCount activeCount}
* method to get an estimate of how big the array should be, however
* if the array is too short to hold all the threads, the extra threads
* are silently ignored. If it is critical to obtain every active
* thread in the current thread's thread group and its subgroups, the
* invoker should verify that the returned int value is strictly less
* than the length of {@code tarray}.
* 如果数组大小不够,会忽略多余的线程
*
*
Due to the inherent race condition in this method, it is recommended
* that the method only be used for debugging and monitoring purposes.
*
* @param tarray
* an array into which to put the list of threads
*
* @return the number of threads put into the array
*
* @throws SecurityException
* if {@link java.lang.ThreadGroup#checkAccess} determines that
* the current thread cannot access its thread group
*/
public static int enumerate(Thread tarray[]) {
return currentThread().getThreadGroup().enumerate(tarray);
}
join
/**
* Waits at most {@code millis} milliseconds for this thread to
* die. A timeout of {@code 0} means to wait forever.
* 最多等待指定毫秒数这个线程死亡,然后继续执行,参数 0 表示永远等待
*
* This implementation uses a loop of {@code this.wait} calls
* conditioned on {@code this.isAlive}. As a thread terminates the
* {@code this.notifyAll} method is invoked. It is recommended that
* applications not use {@code wait}, {@code notify}, or
* {@code notifyAll} on {@code Thread} instances.
* 使用 wait 方法和 isAlive 方法循环实现。当线程结束时,会调用自身的 notifyAll 方法。
*
* @param millis
* the time to wait 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.
*/
// 亮点!亮点!亮点!亮点!同步方法,同步当前Thread对象,所以才能在其内部调用wait()
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;
}
}
}
/**
* Waits at most {@code millis} milliseconds plus
* {@code nanos} nanoseconds for this thread to die.
*
*
This implementation uses a loop of {@code this.wait} calls
* conditioned on {@code this.isAlive}. As a thread terminates the
* {@code this.notifyAll} method is invoked. It is recommended that
* applications not use {@code wait}, {@code notify}, or
* {@code notifyAll} on {@code Thread} instances.
*
* @param millis
* the time to wait in milliseconds
*
* @param nanos
* {@code 0-999999} additional nanoseconds to wait
*
* @throws IllegalArgumentException
* if the value of {@code millis} is negative, or the value
* of {@code nanos} is not in the range {@code 0-999999}
*
* @throws InterruptedException
* if any thread has interrupted the current thread. The
* interrupted status of the current thread is
* cleared when this exception is thrown.
*/
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);
}
/**
* Waits for this thread to die.
*
*
An invocation of this method behaves in exactly the same
* way as the invocation
*
*
* {@linkplain #join(long) join}{@code (0)}
*
*
* @throws InterruptedException
* if any thread has interrupted the current thread. The
* interrupted status of the current thread is
* cleared when this exception is thrown.
*/
public final void join() throws InterruptedException {
join(0);
}
setDaemon、isDaemon
/**
* Marks this thread as either a {@linkplain #isDaemon daemon} thread
* or a user thread. The Java Virtual Machine exits when the only
* threads running are all daemon threads.
* 标记线程为用户线程或者守护线程
*
* This method must be invoked before the thread is started.
* 该方法必须在 start 方法之前执行
*
* @param on
* if {@code true}, marks this thread as a daemon thread
*
* @throws IllegalThreadStateException
* if this thread is {@linkplain #isAlive alive}
*
* @throws SecurityException
* if {@link #checkAccess} determines that the current
* thread cannot modify this thread
*/
public final void setDaemon(boolean on) {
checkAccess();
if (isAlive()) {
throw new IllegalThreadStateException();
}
daemon = on;
}
/**
* Tests if this thread is a daemon thread.
* 返回是否时守护线程
*
* @return true
if this thread is a daemon thread;
* false
otherwise.
* @see #setDaemon(boolean)
*/
public final boolean isDaemon() {
return daemon;
}
checkAccess
/**
* Determines if the currently running thread has permission to
* modify this thread.
* 判断当前执行线程是否有权限修改这个线程
*
* If there is a security manager, its checkAccess
method
* is called with this thread as its argument. This may result in
* throwing a SecurityException
.
*
* @exception SecurityException if the current thread is not allowed to
* access this thread.
* @see SecurityManager#checkAccess(Thread)
*/
public final void checkAccess() {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkAccess(this);
}
}
toString
略
getContextClassLoader、setContextClassLoader
/**
* Returns the context ClassLoader for this Thread. The context
* ClassLoader is provided by the creator of the thread for use
* by code running in this thread when loading classes and resources.
* If not {@linkplain #setContextClassLoader set}, the default is the
* ClassLoader context of the parent Thread. The context ClassLoader of the
* primordial thread is typically set to the class loader used to load the
* application.
* 返回这个线程的上下文类加载器。上下文类加载器有这个线程的创建者提供
*
* If a security manager is present, and the invoker's class loader is not
* {@code null} and is not the same as or an ancestor of the context class
* loader, then this method invokes the security manager's {@link
* SecurityManager#checkPermission(java.security.Permission) checkPermission}
* method with a {@link RuntimePermission RuntimePermission}{@code
* ("getClassLoader")} permission to verify that retrieval of the context
* class loader is permitted.
*
*
* @return the context ClassLoader for this Thread, or {@code null}
* indicating the system class loader (or, failing that, the
* bootstrap class loader)
*
* @throws SecurityException
* if the current thread cannot get the context ClassLoader
*
* @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;
}
/**
* Sets the context ClassLoader for this Thread. The context
* ClassLoader can be set when a thread is created, and allows
* the creator of the thread to provide the appropriate class loader,
* through {@code getContextClassLoader}, to code running in the thread
* when loading classes and resources.
* 变更类加载器
*
*
If a security manager is present, its {@link
* SecurityManager#checkPermission(java.security.Permission) checkPermission}
* method is invoked with a {@link RuntimePermission RuntimePermission}{@code
* ("setContextClassLoader")} permission to see if setting the context
* ClassLoader is permitted.
*
* @param cl
* the context ClassLoader for this Thread, or null indicating the
* system class loader (or, failing that, the bootstrap class loader)
*
* @throws SecurityException
* if the current thread cannot set the context ClassLoader
*
* @since 1.2
*/
public void setContextClassLoader(ClassLoader cl) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new RuntimePermission("setContextClassLoader"));
}
contextClassLoader = cl;
}
holdsLock
/**
* Returns true if and only if the current thread holds the
* monitor lock on the specified object.
* 返回是否持有指定对象锁
*
* This method is designed to allow a program to assert that
* the current thread already holds a specified lock:
*
* assert Thread.holdsLock(obj);
*
*
* @param obj the object on which to test lock ownership
* @throws NullPointerException if obj is null
* @return true if the current thread holds the monitor lock on
* the specified object.
* @since 1.4
*/
public static native boolean holdsLock(Object obj);
简单介绍了 Thread 类的主要方法之后,我们再来看下,线程状态的转换。
上文提到,状态一共有 NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING 和 TERMINATED 六种。状态之间的转换如下: