經(jīng)常在分析 ANR 問題的時候,需要對線程狀態(tài)了解得比較清楚,才能進一步分析問題萄喳。
線程狀態(tài)
java 的線程狀態(tài)定義在 Thread.State 中芬骄,如下:
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:
* <ul>
* <li>{@link Object#wait() Object.wait} with no timeout</li>
* <li>{@link #join() Thread.join} with no timeout</li>
* <li>{@link LockSupport#park() LockSupport.park}</li>
* </ul>
*
* <p>A thread in the waiting state is waiting for another thread to
* perform a particular action.
*
* For example, a thread that has called <tt>Object.wait()</tt>
* on an object is waiting for another thread to call
* <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
* that object. A thread that has called <tt>Thread.join()</tt>
* 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:
* <ul>
* <li>{@link #sleep Thread.sleep}</li>
* <li>{@link Object#wait(long) Object.wait} with timeout</li>
* <li>{@link #join(long) Thread.join} with timeout</li>
* <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
* <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
* </ul>
*/
TIMED_WAITING,
/**
* Thread state for a terminated thread.
* The thread has completed execution.
*/
TERMINATED;
}
其中猾愿,相關狀態(tài)如下:
狀態(tài) | 說明 |
---|---|
NEW | 線程創(chuàng)建,但是還沒有start() |
RUNNABLE | 線程執(zhí)行或者在等待系統(tǒng)資源账阻,例如CPU資源 |
BLOCKED | 線程在等待其它線程釋放一個鎖蒂秘,則會進入 Blocked 狀態(tài)。例如在等待一個同步代碼塊的鎖淘太,獲得鎖則進入 Runnable 狀態(tài) |
WAITING | 線程在等待一個其它線程喚醒它姻僧。可能是調用了 Object.wait(),Thread.join() ,LockSupport.part() |
TIMED_WAITING | 同上蒲牧,只不過方法換成了 Object.wait(timeOut) ,Thread.join(millis<br />) ,LockSupport.part(deadline<br />) |
TERMINATED | 線程銷毀 |
java 的線程狀態(tài)也是讀取 native 線程的狀態(tài)撇贺,如下:
//Thread.java
public State getState() {
// get current thread state
// Android-changed: Replace unused threadStatus field with started field.
// Use Android specific nativeGetStatus() method. See comment on started field for more
// information.
// return sun.misc.VM.toThreadState(threadStatus);
return State.values()[nativeGetStatus(started)];
}
private native int nativeGetStatus(boolean hasBeenStarted);
對應的 jni 實現(xiàn),在 java_lang_Thread.cc 中:
static jint Thread_nativeGetStatus(JNIEnv* env, jobject java_thread, jboolean has_been_started) {
// Ordinals from Java's Thread.State.
const jint kJavaNew = 0;
const jint kJavaRunnable = 1;
const jint kJavaBlocked = 2;
const jint kJavaWaiting = 3;
const jint kJavaTimedWaiting = 4;
const jint kJavaTerminated = 5;
ScopedObjectAccess soa(env);
ThreadState internal_thread_state =
(has_been_started ? ThreadState::kTerminated : ThreadState::kStarting);
MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
Thread* thread = Thread::FromManagedThread(soa, java_thread);
if (thread != nullptr) {
internal_thread_state = thread->GetState();
}
switch (internal_thread_state) {
case ThreadState::kTerminated: return kJavaTerminated;
case ThreadState::kRunnable: return kJavaRunnable;
case ThreadState::kObsoleteRunnable: break; // Obsolete value.
case ThreadState::kTimedWaiting: return kJavaTimedWaiting;
case ThreadState::kSleeping: return kJavaTimedWaiting;
case ThreadState::kBlocked: return kJavaBlocked;
case ThreadState::kWaiting: return kJavaWaiting;
case ThreadState::kStarting: return kJavaNew;
case ThreadState::kNative: return kJavaRunnable;
case ThreadState::kWaitingForTaskProcessor: return kJavaWaiting;
case ThreadState::kWaitingForLockInflation: return kJavaWaiting;
case ThreadState::kWaitingForGcToComplete: return kJavaWaiting;
case ThreadState::kWaitingPerformingGc: return kJavaWaiting;
case ThreadState::kWaitingForCheckPointsToRun: return kJavaWaiting;
case ThreadState::kWaitingForDebuggerSend: return kJavaWaiting;
case ThreadState::kWaitingForDebuggerToAttach: return kJavaWaiting;
case ThreadState::kWaitingInMainDebuggerLoop: return kJavaWaiting;
case ThreadState::kWaitingForDebuggerSuspension: return kJavaWaiting;
case ThreadState::kWaitingForDeoptimization: return kJavaWaiting;
case ThreadState::kWaitingForGetObjectsAllocated: return kJavaWaiting;
case ThreadState::kWaitingForJniOnLoad: return kJavaWaiting;
case ThreadState::kWaitingForSignalCatcherOutput: return kJavaWaiting;
case ThreadState::kWaitingInMainSignalCatcherLoop: return kJavaWaiting;
case ThreadState::kWaitingForMethodTracingStart: return kJavaWaiting;
case ThreadState::kWaitingForVisitObjects: return kJavaWaiting;
case ThreadState::kWaitingWeakGcRootRead: return kJavaRunnable;
case ThreadState::kWaitingForGcThreadFlip: return kJavaWaiting;
case ThreadState::kNativeForAbort: return kJavaWaiting;
case ThreadState::kSuspended: return kJavaRunnable;
// Don't add a 'default' here so the compiler can spot incompatible enum changes.
}
LOG(ERROR) << "Unexpected thread state: " << internal_thread_state;
return -1; // Unreachable.
}
所以在 C++ 層中造成,對應的相關狀態(tài)如下:
enum class ThreadState : uint8_t {
// `kRunnable` was previously 67 but it is now set to 0 so that we do not need to extract
// flags from the thread's `state_and_flags` to check for any flag being set while Runnable.
// Note: All atomic accesses for a location should use the same data size,
// so the incorrect old approach of reading just 16 bits has been rewritten.
// Java
// Thread.State JDWP state
kTerminated = 66, // TERMINATED TS_ZOMBIE Thread.run has returned, but Thread* still around
kRunnable = 0, // RUNNABLE TS_RUNNING runnable
kObsoleteRunnable = 67, // --- --- obsolete value
kTimedWaiting = 68, // TIMED_WAITING TS_WAIT in Object.wait() with a timeout
kSleeping, // TIMED_WAITING TS_SLEEPING in Thread.sleep()
kBlocked, // BLOCKED TS_MONITOR blocked on a monitor
kWaiting, // WAITING TS_WAIT in Object.wait()
kWaitingForLockInflation, // WAITING TS_WAIT blocked inflating a thin-lock
kWaitingForTaskProcessor, // WAITING TS_WAIT blocked waiting for taskProcessor
kWaitingForGcToComplete, // WAITING TS_WAIT blocked waiting for GC
kWaitingForCheckPointsToRun, // WAITING TS_WAIT GC waiting for checkpoints to run
kWaitingPerformingGc, // WAITING TS_WAIT performing GC
kWaitingForDebuggerSend, // WAITING TS_WAIT blocked waiting for events to be sent
kWaitingForDebuggerToAttach, // WAITING TS_WAIT blocked waiting for debugger to attach
kWaitingInMainDebuggerLoop, // WAITING TS_WAIT blocking/reading/processing debugger events
kWaitingForDebuggerSuspension, // WAITING TS_WAIT waiting for debugger suspend all
kWaitingForJniOnLoad, // WAITING TS_WAIT waiting for execution of dlopen and JNI on load code
kWaitingForSignalCatcherOutput, // WAITING TS_WAIT waiting for signal catcher IO to complete
kWaitingInMainSignalCatcherLoop, // WAITING TS_WAIT blocking/reading/processing signals
kWaitingForDeoptimization, // WAITING TS_WAIT waiting for deoptimization suspend all
kWaitingForMethodTracingStart, // WAITING TS_WAIT waiting for method tracing to start
kWaitingForVisitObjects, // WAITING TS_WAIT waiting for visiting objects
kWaitingForGetObjectsAllocated, // WAITING TS_WAIT waiting for getting the number of allocated objects
kWaitingWeakGcRootRead, // WAITING TS_WAIT waiting on the GC to read a weak root
kWaitingForGcThreadFlip, // WAITING TS_WAIT waiting on the GC thread flip (CC collector) to finish
kNativeForAbort, // WAITING TS_WAIT checking other threads are not run on abort.
kStarting, // NEW TS_WAIT native thread started, not yet ready to run managed code
kNative, // RUNNABLE TS_RUNNING running in a JNI native method
kSuspended, // RUNNABLE TS_RUNNING suspended by GC or debugger
};
可以看到 C++ 里面的線程狀態(tài)會有更多的細節(jié)显熏。其中,包括 kNative 表示正在執(zhí)行 native 方法晒屎。
<a name="yFpdf"></a>
ANR 日志中線程狀態(tài)說明
類似的 ANR 日志如下:
"main" prio=5 tid=1 Native
| group="main" sCount=1 dsCount=0 flags=1 obj=0x75af8d38 self=0xefe71e00
| sysTid=5423 nice=-10 cgrp=default sched=0/0 handle=0xf0273dc0
| state=S schedstat=( 61207235540 31084517122 178273 ) utm=4704 stm=1416 core=1 HZ=100
| stack=0xff039000-0xff03b000 stackSize=8192KB
| held mutexes=
kernel: (couldn't read /proc/self/task/5423/stack)
native: #00 pc 00052188 /apex/com.android.runtime/lib/bionic/libc.so (syscall+28)
native: #01 pc 0005750f /apex/com.android.runtime/lib/bionic/libc.so (__futex_wait_ex(void volatile*, bool, int, bool, timespec const*)+90)
native: #02 pc 000a07f3 /apex/com.android.runtime/lib/bionic/libc.so (pthread_cond_wait+32)
native: #03 pc 0006949b /data/app/com.starify.ola.android-62F7MEKjVCxvF8JrKvQgEw==/lib/arm/libalivc_conan.so (std::__ndk1::condition_variable::wait(std::__ndk1::unique_lock<std::__ndk1::mutex>&)+26)
native: #04 pc 00069c3d /data/app/com.starify.ola.android-62F7MEKjVCxvF8JrKvQgEw==/lib/arm/libalivc_conan.so (std::__ndk1::__assoc_sub_state::__sub_wait(std::__ndk1::unique_lock<std::__ndk1::mutex>&)+32)
native: #05 pc 00069bb3 /data/app/com.starify.ola.android-62F7MEKjVCxvF8JrKvQgEw==/lib/arm/libalivc_conan.so (std::__ndk1::__assoc_sub_state::copy()+38)
native: #06 pc 00069dd7 /data/app/com.starify.ola.android-62F7MEKjVCxvF8JrKvQgEw==/lib/arm/libalivc_conan.so (std::__ndk1::future<void>::get()+12)
native: #07 pc 0029499b /data/app/com.starify.ola.android-62F7MEKjVCxvF8JrKvQgEw==/lib/arm/libugsv.so (???)
native: #08 pc 0009786b /data/app/com.starify.ola.android-62F7MEKjVCxvF8JrKvQgEw==/lib/arm/libugsv.so (???)
native: #09 pc 0008f6bd /data/app/com.starify.ola.android-62F7MEKjVCxvF8JrKvQgEw==/lib/arm/libugsv.so (???)
native: #10 pc 0009122b /data/app/com.starify.ola.android-62F7MEKjVCxvF8JrKvQgEw==/lib/arm/libugsv.so (???)
其中喘蟆,第一行 "main" prio=5 tid=1 Native,表示當前線程的狀態(tài)是 Native鼓鲁。那么在 ANR 日志中蕴轨,線程的狀態(tài)細分如下:
java Thread 的狀態(tài) | C++ 層Thread 狀態(tài) | 說明 |
---|---|---|
NEW | INITIALIZING | 新建,正在分配資源 |
NEW | STARING | 新建骇吭,正在啟動 |
RUNNABLE | RUNING/RUNNABLE | 線程創(chuàng)建或者正在運行 |
RUNNABLE | NATIVE | 正在執(zhí)行 JNI 方法 |
RUNNABLE | SUSPENDED | 現(xiàn)在掛起橙弱,一般是GC導致 |
BLOCKED | MOINITOR | 線程阻塞,等待其它線程釋放對象鎖 |
WAITING | WAIT | 執(zhí)行了無超時參數(shù)的 wait() 等方法 |
WAITING | VMWAIT | 正在等待 VM 資源 |
TERMINATED | ZOMBIE | 線程銷毀 |
其中,我們主要關心的狀態(tài)是 MOINITOR棘脐,WAIT斜筐,如果主線程是這個狀態(tài),那么 ANR 的原因就是主線程被阻塞或者在等待子線程釋放鎖蛀缝。