提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
一、java创建一个线程的流程
创建线程的流程
- 这一步很简单,大家都知道java创建线程常用的两种方法继承Thread类和实现Runnable接口,例如:
public class ThreadDemo extends Thread{ @Override public void run() { System.out.println("hello world"); } } class Demo{ public static void main(String[] args) { ThreadDemo threadDemo = new ThreadDemo(); threadDemo.start(); } }
这里我们可以看下hreadDemo.start();的源码部分
我们可以看到线程的启动方法是start0(),而这个start0被native()修饰,说明他是一个本地方法。下面我们下载openJDK的源码查看以下start0的调用链路是怎么样的。
下载地址:[https://hg.openjdk.org/jdk8/jdk8/jdk/file]
java类中使用了native关键字的一般会有对应的<类名>.c文件与之对应,是C语言的源码文件,主要用于实现 Java 虚拟机中的一些本地方法或者 JNI 接口。
下面我们找到Thread.c文件,对应源码部分如下:
static JNINativeMethod methods[] = {
{"start0", "()V", (void *)&JVM_StartThread},
{"stop0", "(" OBJ ")V", (void *)&JVM_StopThread},
{"isAlive", "()Z", (void *)&JVM_IsThreadAlive},
{"suspend0", "()V", (void *)&JVM_SuspendThread},
{"resume0", "()V", (void *)&JVM_ResumeThread},
{"setPriority0", "(I)V", (void *)&JVM_SetThreadPriority},
{"yield", "()V", (void *)&JVM_Yield},
{"sleep", "(J)V", (void *)&JVM_Sleep},
{"currentThread", "()" THD, (void *)&JVM_CurrentThread},
{"countStackFrames", "()I", (void *)&JVM_CountStackFrames},
{"interrupt0", "()V", (void *)&JVM_Interrupt},
{"isInterrupted", "(Z)Z", (void *)&JVM_IsInterrupted},
{"holdsLock", "(" OBJ ")Z", (void *)&JVM_HoldsLock},
{"getThreads", "()[" THD, (void *)&JVM_GetAllThreads},
{"dumpThreads", "([" THD ")[[" STE, (void *)&JVM_DumpThreads},
{"setNativeName", "(" STR ")V", (void *)&JVM_SetNativeThreadName},
};
我们发下start0调用的是JVM的StartThread函数 。
下面我们来接着跟JVM_StartThread函数的源码部分,java在使用JNI(Java Native Interface)调用本地函数时,函数指针一般定义在jvm.h头文件中,代码部分如下:
/*
* java.lang.Thread
*/
JNIEXPORT void JNICALL
JVM_StartThread(JNIEnv *env, jobject thread);
再看jvm.cpp的源码部分
在这里我们可以看到源码在这里使用 new 关键字创建一个新的 JavaThread 对象,并将其构造函数的参数设置为 &thread_entry 和 sz。其中,&thread_entry 表示一个函数指针,指向一个用于执行线程的函数,sz 表示线程的栈空间大小。接下来我们需要去thread.cpp中看JavaThread的源码实现部分。
最终调用OS的create_thread创建线程
二、线程状态
下面我们根据源码和上图的状态变化,分析以下线程的几个状态。
1. 实例化线程(NEW状态)
首先我看下线程初始初始状态,当我们new Thread()实例时,我们从源码中可以看到
/* Java thread status for tools,
* initialized to indicate thread 'not yet started'
*/
private volatile int threadStatus = 0;
在Thread.java对象中有个私有属性threadStatus,它的初始状态为0,根据上面的注释“initialized to indicate thread ‘not yet started’,翻译:已初始化以指示线程’尚未启动’”,下面我们继续追这个‘尚未启动’究竟是个什么状态。
/**
* Returns the state of this thread.
* This method is designed for use in monitoring of the system state,
* not for synchronization control.
*
* @return this thread's state.
* @since 1.5
*/
public State getState() {
// get current thread state
return sun.misc.VM.toThreadState(threadStatus);
}
同样在Thread.java类中有一个getState()方法,方法里是根据threadStatus属性获取了线程状态,那么我们就可以看threadStatus=0的时候,线程是什么状态了。
public static Thread.State toThreadState(int var0) {
if ((var0 & 4) != 0) {
return State.RUNNABLE;
} else if ((var0 & 1024) != 0) {
return State.BLOCKED;
} else if ((var0 & 16) != 0) {
return State.WAITING;
} else if ((var0 & 32) != 0) {
return State.TIMED_WAITING;
} else if ((var0 & 2) != 0) {
return State.TERMINATED;
} else {
return (var0 & 1) == 0 ? State.NEW : State.RUNNABLE;
}
}
threadStatus=0传入toThreadState(int)方法,会执行到else块中,0&1=0,所以线程初始状态是为NEW。
2. RUNNABLE状态
根据上面的流程图,线程在NEW状态下执行start()方法,线程变为RUNNABLE状态。
我们在上面分析start方法调用native部分的源码,这里为了方便查看我们把start方法源码贴到下方
/**
* Causes this thread to begin execution; the Java Virtual Machine
* calls the <code>run</code> method of this thread.
* <p>
* The result is that two threads are running concurrently: the
* current thread (which returns from the call to the
* <code>start</code> method) and the other thread (which executes its
* <code>run</code> method).
* <p>
* It is never legal to start a thread more than once.
* In particular, a thread may not be restarted once it has completed
* execution.
*
* @exception IllegalThreadStateException if the thread was already
* started.
* @see #run()
* @see #stop()
*/
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".
*/
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 */
}
}
}
从源码可以看出,能够执行start方法的只有线程状态是NEW才可以。java的源码中在启动线程时候并没有改变线程的地方,那很有可能在start0()的本地方法中改变的状态,按着这个想法我们继续跟下start0的源码,通过上面的分析我们已经知道start0方法执行的jvm.cpp中的StartThread函数,代码如下:
JVM_ENTRY(void, JVM_StartThread(JNIEnv* env, jobject jthread))
JVMWrapper("JVM_StartThread");
JavaThread *native_thread = NULL;
// We cannot hold the Threads_lock when we throw an exception,
// due to rank ordering issues. Example: we might need to grab the
// Heap_lock while we construct the exception.
bool throw_illegal_thread_state = false;
// We must release the Threads_lock before we can post a jvmti event
// in Thread::start.
{
// Ensure that the C++ Thread and OSThread structures aren't freed before
// we operate.
MutexLocker mu(Threads_lock);
// Since JDK 5 the java.lang.Thread threadStatus is used to prevent
// re-starting an already started thread, so we should usually find
// that the JavaThread is null. However for a JNI attached thread
// there is a small window between the Thread object being created
// (with its JavaThread set) and the update to its threadStatus, so we
// have to check for this
if (java_lang_Thread::thread(JNIHandles::resolve_non_null(jthread)) != NULL) {
throw_illegal_thread_state = true;
} else {
// We could also check the stillborn flag to see if this thread was already stopped, but
// for historical reasons we let the thread detect that itself when it starts running
jlong size =
java_lang_Thread::stackSize(JNIHandles::resolve_non_null(jthread));
// Allocate the C++ Thread structure and create the native thread. The
// stack size retrieved from java is signed, but the constructor takes
// size_t (an unsigned type), so avoid passing negative values which would
// result in really large stacks.
size_t sz = size > 0 ? (size_t) size : 0;
native_thread = new JavaThread(&thread_entry, sz);
// At this point it may be possible that no osthread was created for the
// JavaThread due to lack of memory. Check for this situation and throw
// an exception if necessary. Eventually we may want to change this so
// that we only grab the lock if the thread was created successfully -
// then we can also do this check and throw the exception in the
// JavaThread constructor.
if (native_thread->osthread() != NULL) {
// Note: the current thread is not being used within "prepare".
native_thread->prepare(jthread);
}
}
}
if (throw_illegal_thread_state) {
THROW(vmSymbols::java_lang_IllegalThreadStateException());
}
assert(native_thread != NULL, "Starting null thread?");
if (native_thread->osthread() == NULL) {
// No one should hold a reference to the 'native_thread'.
delete native_thread;
if (JvmtiExport::should_post_resource_exhausted()) {
JvmtiExport::post_resource_exhausted(
JVMTI_RESOURCE_EXHAUSTED_OOM_ERROR | JVMTI_RESOURCE_EXHAUSTED_THREADS,
"unable to create new native thread");
}
THROW_MSG(vmSymbols::java_lang_OutOfMemoryError(),
"unable to create new native thread");
}
#if INCLUDE_JFR
if (JfrRecorder::is_recording() && EventThreadStart::is_enabled() &&
EventThreadStart::is_stacktrace_enabled()) {
JfrThreadLocal* tl = native_thread->jfr_thread_local();
// skip Thread.start() and Thread.start0()
tl->set_cached_stack_trace_id(JfrStackTraceRepository::record(thread, 2));
}
#endif
Thread::start(native_thread);
JVM_END
上面代码可以看到启动线程执行的是Thread::start(native_thread);这行代码,下面我们去thread.cpp文件找到这个start函数源码,看看干了些什么事情呢?
void Thread::start(Thread* thread) {
trace("start", thread);
// Start is different from resume in that its safety is guaranteed by context or
// being called from a Java method synchronized on the Thread object.
if (!DisableStartThread) {
if (thread->is_Java_thread()) {
// Initialize the thread state to RUNNABLE before starting this thread.
// Can not set it after the thread started because we do not know the
// exact thread state at that time. It could be in MONITOR_WAIT or
// in SLEEPING or some other state.
java_lang_Thread::set_thread_status(((JavaThread*)thread)->threadObj(),
java_lang_Thread::RUNNABLE);
}
os::start_thread(thread);
}
}
在这里我们可以看到,它把线程状态改为了枚举RUNNABLE(与java线程对象状态对应关系请参考:简述java线程类Thread的状态获取逻辑),并且在系统中开启了线程。
线程的RUNNING和READY状态
其实在java中RUNNING和READY两个状态都属于RUNNABLE状态,只是这两个状态是系统底层的实现,对JVM是不可见的。
- RUNNING 状态:表示当前线程正在运行,也就是当前线程正在执行其代码逻辑。
- READY 状态:表示线程已经准备好运行,但是还没有得到 CPU 时间片。这通常是因为系统中有其他线程正在执行,所以当前线程需要等待其他线程执行完毕并释放 CPU 时间片后才能执行。
3. BLOCKED状态
使线程变更为BLOCKED状态的有几个场景,下面一一列举看下:
synchronized
在Java中,synchronized方法或代码块是用来保证多个线程之间的同步的机制之一。当一个线程进入synchronized方法或代码块时,它会尝试获取该对象的锁。如果锁已经被其他线程占用,则当前线程会进入BLOCKED状态,直到其他线程释放该对象的锁。
具体来说,当一个线程进入synchronized方法或代码块时,它会首先尝试获取该对象的监视器锁(也称为内部锁或对象锁)。如果该对象的锁已经被其他线程占用,则当前线程会被阻塞并进入BLOCKED状态,等待其他线程释放该锁。
当其他线程释放该对象的锁时,处于BLOCKED状态的线程会重新尝试获取锁并继续执行。如果当前线程成功获取到锁,则它会进入RUNNABLE状态,继续执行synchronized方法或代码块中的代码。如果当前线程无法获取到锁,则它会继续保持BLOCKED状态,直到下一次有机会获取到该锁。
那么我们就来关注一下JVM的源码ObjectMonitor::enter(获取监视器锁)的源码,看下是否有处理线程状态的相关代码
void ATTR ObjectMonitor::enter(TRAPS) {
// The following code is ordered to check the most common cases first
// and to reduce RTS->RTO cache line upgrades on SPARC and IA32 processors.
Thread * const Self = THREAD ;
void * cur ;
cur = Atomic::cmpxchg_ptr (Self, &_owner, NULL) ;
if (cur == NULL) {
// Either ASSERT _recursions == 0 or explicitly set _recursions = 0.
assert (_recursions == 0 , "invariant") ;
assert (_owner == Self, "invariant") ;
// CONSIDER: set or assert OwnerIsThread == 1
return ;
}
if (cur == Self) {
// TODO-FIXME: check for integer overflow! BUGID 6557169.
_recursions ++ ;
return ;
}
if (Self->is_lock_owned ((address)cur)) {
assert (_recursions == 0, "internal state error");
_recursions = 1 ;
// Commute owner from a thread-specific on-stack BasicLockObject address to
// a full-fledged "Thread *".
_owner = Self ;
OwnerIsThread = 1 ;
return ;
}
// We've encountered genuine contention.
assert (Self->_Stalled == 0, "invariant") ;
Self->_Stalled = intptr_t(this) ;
// Try one round of spinning *before* enqueueing Self
// and before going through the awkward and expensive state
// transitions. The following spin is strictly optional ...
// Note that if we acquire the monitor from an initial spin
// we forgo posting JVMTI events and firing DTRACE probes.
if (Knob_SpinEarly && TrySpin (Self) > 0) {
assert (_owner == Self , "invariant") ;
assert (_recursions == 0 , "invariant") ;
assert (((oop)(object()))->mark() == markOopDesc::encode(this), "invariant") ;
Self->_Stalled = 0 ;
return ;
}
assert (_owner != Self , "invariant") ;
assert (_succ != Self , "invariant") ;
assert (Self->is_Java_thread() , "invariant") ;
JavaThread * jt = (JavaThread *) Self ;
assert (!SafepointSynchronize::is_at_safepoint(), "invariant") ;
assert (jt->thread_state() != _thread_blocked , "invariant") ;
assert (this->object() != NULL , "invariant") ;
assert (_count >= 0, "invariant") ;
// Prevent deflation at STW-time. See deflate_idle_monitors() and is_busy().
// Ensure the object-monitor relationship remains stable while there's contention.
Atomic::inc_ptr(&_count);
JFR_ONLY(JfrConditionalFlushWithStacktrace<EventJavaMonitorEnter> flush(jt);)
EventJavaMonitorEnter event;
if (event.should_commit()) {
event.set_monitorClass(((oop)this->object())->klass());
event.set_address((uintptr_t)(this->object_addr()));
}
{ // Change java thread status to indicate blocked on monitor enter.
JavaThreadBlockedOnMonitorEnterState jtbmes(jt, this);
Self->set_current_pending_monitor(this);
DTRACE_MONITOR_PROBE(contended__enter, this, object(), jt);
if (JvmtiExport::should_post_monitor_contended_enter()) {
JvmtiExport::post_monitor_contended_enter(jt, this);
// The current thread does not yet own the monitor and does not
// yet appear on any queues that would get it made the successor.
// This means that the JVMTI_EVENT_MONITOR_CONTENDED_ENTER event
// handler cannot accidentally consume an unpark() meant for the
// ParkEvent associated with this ObjectMonitor.
}
OSThreadContendState osts(Self->osthread());
ThreadBlockInVM tbivm(jt);
// TODO-FIXME: change the following for(;;) loop to straight-line code.
for (;;) {
jt->set_suspend_equivalent();
// cleared by handle_special_suspend_equivalent_condition()
// or java_suspend_self()
EnterI (THREAD) ;
if (!ExitSuspendEquivalent(jt)) break ;
//
// We have acquired the contended monitor, but while we were
// waiting another thread suspended us. We don't want to enter
// the monitor while suspended because that would surprise the
// thread that suspended us.
//
_recursions = 0 ;
_succ = NULL ;
exit (false, Self) ;
jt->java_suspend_self();
}
Self->set_current_pending_monitor(NULL);
// We cleared the pending monitor info since we've just gotten past
// the enter-check-for-suspend dance and we now own the monitor free
// and clear, i.e., it is no longer pending. The ThreadBlockInVM
// destructor can go to a safepoint at the end of this block. If we
// do a thread dump during that safepoint, then this thread will show
// as having "-locked" the monitor, but the OS and java.lang.Thread
// states will still report that the thread is blocked trying to
// acquire it.
}
Atomic::dec_ptr(&_count);
assert (_count >= 0, "invariant") ;
Self->_Stalled = 0 ;
// Must either set _recursions = 0 or ASSERT _recursions == 0.
assert (_recursions == 0 , "invariant") ;
assert (_owner == Self , "invariant") ;
assert (_succ != Self , "invariant") ;
assert (((oop)(object()))->mark() == markOopDesc::encode(this), "invariant") ;
// The thread -- now the owner -- is back in vm mode.
// Report the glorious news via TI,DTrace and jvmstat.
// The probe effect is non-trivial. All the reportage occurs
// while we hold the monitor, increasing the length of the critical
// section. Amdahl's parallel speedup law comes vividly into play.
//
// Another option might be to aggregate the events (thread local or
// per-monitor aggregation) and defer reporting until a more opportune
// time -- such as next time some thread encounters contention but has
// yet to acquire the lock. While spinning that thread could
// spinning we could increment JVMStat counters, etc.
DTRACE_MONITOR_PROBE(contended__entered, this, object(), jt);
if (JvmtiExport::should_post_monitor_contended_entered()) {
JvmtiExport::post_monitor_contended_entered(jt, this);
// The current thread already owns the monitor and is not going to
// call park() for the remainder of the monitor enter protocol. So
// it doesn't matter if the JVMTI_EVENT_MONITOR_CONTENDED_ENTERED
// event handler consumed an unpark() issued by the thread that
// just exited the monitor.
}
if (event.should_commit()) {
event.set_previousOwner((uintptr_t)_previous_owner_tid);
event.commit();
}
if (ObjectMonitor::_sync_ContendedLockAttempts != NULL) {
ObjectMonitor::_sync_ContendedLockAttempts->inc() ;
}
}
我们看到有一行JavaThreadBlockedOnMonitorEnterState jtbmes(jt, this);这个代码,如下图,在监视器锁被其他线程占用是会最终执行这行代码,而根据注释我们也能看出来,这里要把这个java线程的状态变为blocked。
下面再看下JavaThreadBlockedOnMonitorEnterState这个类的代码
// Change status to blocked on (re-)entering a synchronization block
class JavaThreadBlockedOnMonitorEnterState : public JavaThreadStatusChanger {
private:
ThreadStatistics* _stat;
bool _active;
static bool contended_enter_begin(JavaThread *java_thread) {
set_thread_status(java_thread, java_lang_Thread::BLOCKED_ON_MONITOR_ENTER);
ThreadStatistics* stat = java_thread->get_thread_stat();
stat->contended_enter();
bool active = ThreadService::is_thread_monitoring_contention();
if (active) {
stat->contended_enter_begin();
}
return active;
}
public:
// java_thread is waiting thread being blocked on monitor reenter.
// Current thread is the notifying thread which holds the monitor.
static bool wait_reenter_begin(JavaThread *java_thread, ObjectMonitor *obj_m) {
assert((java_thread != NULL), "Java thread should not be null here");
bool active = false;
if (is_alive(java_thread) && ServiceUtil::visible_oop((oop)obj_m->object())) {
active = contended_enter_begin(java_thread);
}
return active;
}
static void wait_reenter_end(JavaThread *java_thread, bool active) {
if (active) {
java_thread->get_thread_stat()->contended_enter_end();
}
set_thread_status(java_thread, java_lang_Thread::RUNNABLE);
}
JavaThreadBlockedOnMonitorEnterState(JavaThread *java_thread, ObjectMonitor *obj_m) :
_stat(NULL), _active(false), JavaThreadStatusChanger(java_thread) {
assert((java_thread != NULL), "Java thread should not be null here");
// Change thread status and collect contended enter stats for monitor contended
// enter done for external java world objects and it is contended. All other cases
// like for vm internal objects and for external objects which are not contended
// thread status is not changed and contended enter stat is not collected.
_active = false;
if (is_alive() && ServiceUtil::visible_oop((oop)obj_m->object()) && obj_m->contentions() > 0) {
_stat = java_thread->get_thread_stat();
_active = contended_enter_begin(java_thread);
}
}
~JavaThreadBlockedOnMonitorEnterState() {
if (_active) {
_stat->contended_enter_end();
}
}
};
参考上面的代码,在实例化JavaThreadBlockedOnMonitorEnterState类的时候,有个判断逻辑:if (is_alive() && ServiceUtil::visible_oop((oop)obj_m->object()) && obj_m->contentions() > 0),而这三个判断条件分别是:
is_alive():检查线程是否处于活动状态
ServiceUtil::visible_oop((oop)obj_m->object()):检查锁对象是否可见,即锁对象是否还存在。
obj_m->contentions() > 0:该条件检查锁对象是否有竞争。
因为没有获取到监视器锁的线程这三个条件应该都是满足的,所以最终在contended_enter_begin(java_thread)方法中的set_thread_status(java_thread, java_lang_Thread::BLOCKED_ON_MONITOR_ENTER);修改的线程状态为BLOCKED。
Object.wait()
Object类中wait()方法的调用链路:wait() -> wait(0) -> native void wait(long timeout),最终调用的是本地方法wait。
下面我们看下JDK中wait(long timeout)的实现
//Object.c
static JNINativeMethod methods[] = {
{"hashCode", "()I", (void *)&JVM_IHashCode},
{"wait", "(J)V", (void *)&JVM_MonitorWait},
{"notify", "()V", (void *)&JVM_MonitorNotify},
{"notifyAll", "()V", (void *)&JVM_MonitorNotifyAll},
{"clone", "()Ljava/lang/Object;", (void *)&JVM_Clone},
};
//jvm.h
JNIEXPORT void JNICALL
JVM_MonitorWait(JNIEnv *env, jobject obj, jlong ms);
//jvm.cpp
JVM_ENTRY(void, JVM_MonitorWait(JNIEnv* env, jobject handle, jlong ms))
JVMWrapper("JVM_MonitorWait");
Handle obj(THREAD, JNIHandles::resolve_non_null(handle));
JavaThreadInObjectWaitState jtiows(thread, ms != 0);
if (JvmtiExport::should_post_monitor_wait()) {
JvmtiExport::post_monitor_wait((JavaThread *)THREAD, (oop)obj(), ms);
// The current thread already owns the monitor and it has not yet
// been added to the wait queue so the current thread cannot be
// made the successor. This means that the JVMTI_EVENT_MONITOR_WAIT
// event handler cannot accidentally consume an unpark() meant for
// the ParkEvent associated with this ObjectMonitor.
}
ObjectSynchronizer::wait(obj, ms, CHECK);
JVM_END
//threadService.hpp
class JavaThreadInObjectWaitState : public JavaThreadStatusChanger {
private:
ThreadStatistics* _stat;
bool _active;
public:
JavaThreadInObjectWaitState(JavaThread *java_thread, bool timed) :
JavaThreadStatusChanger(java_thread,
timed ? java_lang_Thread::IN_OBJECT_WAIT_TIMED : java_lang_Thread::IN_OBJECT_WAIT) {
if (is_alive()) {
_stat = java_thread->get_thread_stat();
_active = ThreadService::is_thread_monitoring_contention();
_stat->monitor_wait();
if (_active) {
_stat->monitor_wait_begin();
}
} else {
_active = false;
}
}
~JavaThreadInObjectWaitState() {
if (_active) {
_stat->monitor_wait_end();
}
}
};
线程被调用了 Object.wait() 方法,最终我们在JavaThreadInObjectWaitState对象中看到,这里把线程状态修改成了IN_OBJECT_WAIT,此状态对应java的线程状态为WAITING。那线程是怎么变成BLOCKED状态呢?它发生在线程执行 object.wait() 方法时,线程会释放该对象的锁,等待其他线程获得该对象的锁并执行完相应的 synchronized 块,当其他线程执行完 synchronized 块并释放了该对象的锁后,当前线程就会被唤醒,此时其状态会变为 BLOCKED;
线程被唤醒,那么我们看下notify()或者notifyAll()方法。这里我们追下notifyAll()源码。notifyAll()在Object类中直接调用的native方法,我们直接看JDK中的代码
//jvm.cpp
JVM_ENTRY(void, JVM_MonitorNotifyAll(JNIEnv* env, jobject handle))
JVMWrapper("JVM_MonitorNotifyAll");
Handle obj(THREAD, JNIHandles::resolve_non_null(handle));
ObjectSynchronizer::notifyall(obj, CHECK);
JVM_END
//synchronizer.cpp
void ObjectSynchronizer::notifyall(Handle obj, TRAPS) {
if (UseBiasedLocking) {
BiasedLocking::revoke_and_rebias(obj, false, THREAD);
assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
}
markOop mark = obj->mark();
if (mark->has_locker() && THREAD->is_lock_owned((address)mark->locker())) {
return;
}
ObjectSynchronizer::inflate(THREAD,
obj(),
inflate_cause_notify)->notifyAll(THREAD);
}
//objectMonitor.cpp
void ObjectMonitor::notifyAll(TRAPS) {
//.....省略了一堆代码
if (Policy < 4) {
iterator->wait_reenter_begin(this);
}
//.....省略了一堆代码
}
void ObjectWaiter::wait_reenter_begin(ObjectMonitor *mon) {
JavaThread *jt = (JavaThread *)this->_thread;
_active = JavaThreadBlockedOnMonitorEnterState::wait_reenter_begin(jt, mon);
}
JavaThreadBlockedOnMonitorEnterState对象的wait_reenter_begin方法,我们在讲BLOCKED状态时看到了源码,它会调用contended_enter_begin方法,而该方法干的第一件事就是把线程状态置为BLOCKED_ON_MONITOR_ENTER。
4. WAITING状态
因为上面讲BLOCKED状态已经说到了WAITING的状态变更,这里就不再叙述了。
5. TIMED_WAITING状态
下面我跟下Thread.sleep(long)的方法,从Thread类中看到sleep(long millis)也是一个本地方法,下面我们来看下相关代码
//Thread.c
{"sleep", "(J)V", (void *)&JVM_Sleep}
//jvm.cpp
JVM_ENTRY(void, JVM_Sleep(JNIEnv* env, jclass threadClass, jlong millis))
JVMWrapper("JVM_Sleep");
//...省略部分代码
JavaThreadSleepState jtss(thread);
//...省略部分代码
JVM_END
//threadService.hpp
class JavaThreadSleepState : public JavaThreadStatusChanger {
private:
ThreadStatistics* _stat;
bool _active;
public:
JavaThreadSleepState(JavaThread *java_thread) :
JavaThreadStatusChanger(java_thread, java_lang_Thread::SLEEPING) {
if (is_alive()) {
_stat = java_thread->get_thread_stat();
_active = ThreadService::is_thread_monitoring_contention();
_stat->thread_sleep();
if (_active) {
_stat->thread_sleep_begin();
}
} else {
_active = false;
}
}
~JavaThreadSleepState() {
if (_active) {
_stat->thread_sleep_end();
}
}
};
以上代码最终JavaThreadStatusChanger(java_thread, java_lang_Thread::SLEEPING)这行代码把线程的状态修改成了SLEEPING,而SLEEPING枚举对应的值经过计算对应的就是java Thread类中的TIMED_WAITING状态。
5. TERMINATED状态
Java 线程在终止时会将其状态置为 TERMINATED,具体到源码实现上,线程执行结束后,会调用 Thread::exit() 方法。
Thread 类并没有显式调用 exit() 方法,因为 exit() 方法是 Thread 类的一个私有方法,只能在 Thread 类内部被调用。在 Thread 类中,exit() 方法是被 JVM 虚拟机在特定的时机调用的,例如当 run() 方法执行完成后,JVM 会自动调用 exit() 方法将线程状态置为 TERMINATED。除此之外,还有其他情况也可能会触发 exit() 方法的调用,例如线程被中断或者发生异常等情况。
下面我们看部分相关源码
//thread.cpp
void JavaThread::run() {
// ...省略部分代码
// We call another function to do the rest so we are sure that the stack addresses used
// from there will be lower than the stack base just computed
thread_main_inner();
}
void JavaThread::thread_main_inner() {
assert(JavaThread::current() == this, "sanity check");
assert(this->threadObj() != NULL, "just checking");
// Execute thread entry point unless this thread has a pending exception
// or has been stopped before starting.
// Note: Due to JVM_StopThread we can have pending exceptions already!
if (!this->has_pending_exception() &&
!java_lang_Thread::is_stillborn(this->threadObj())) {
{
ResourceMark rm(this);
this->set_native_thread_name(this->get_thread_name());
}
HandleMark hm(this);
this->entry_point()(this, this);
}
DTRACE_THREAD_PROBE(stop, this);
this->exit(false);
delete this;
}
void JavaThread::exit(bool destroy_vm, ExitType exit_type) {
//...省略部分代码
ensure_join(this);
}
static void ensure_join(JavaThread* thread) {
// ...省略部分代码
// Thread is exiting. So set thread_status field in java.lang.Thread class to TERMINATED.
java_lang_Thread::set_thread_status(threadObj(), java_lang_Thread::TERMINATED);
// ...省略部分代码
}
最终run方法执行完成,JVM会把线程状态置为TERMINATED
总结
新建(New):当线程对象被创建时,它处于新建状态。此时,它还没有被启动,即还没有调用start()方法。
可运行(Runnable):线程被启动后,它进入可运行状态。此时,线程正在运行,或者在等待系统资源(如CPU)分配给它,以便开始运行。
阻塞(Blocked):线程可能会被阻塞,即暂时停止运行。当线程等待某个监视器锁时,它将进入阻塞状态。此时,线程将暂停运行,直到另一个线程释放锁。
等待(Waiting):线程在等待某个条件的出现时,将进入等待状态。当线程调用wait()、join()、park()等方法时,它将进入等待状态。此时,线程将暂停运行,直到满足特定条件。
计时等待(Timed Waiting):线程可以通过调用带有时间参数的wait()、join()、sleep()、parkNanos()、parkUntil()等方法进入计时等待状态。此时,线程将暂停运行一段时间,直到等待时间结束或者满足特定条件。
终止(Terminated):线程的run()方法执行完毕后,线程将进入终止状态。此时,线程将不再运行,并且不可再次启动。