浅析android 线程状态

在分析ANR问题时,第一步就是把/data/anr/traces.txt这个文件adb pull出来分析, 它记录了手机发生ANR时, 各个进程里的所有线程在当时的状态.
典型的情况是:


----- pid 9644 at 2015-12-18 18:06:11 -----
Cmd line: com.tencent.androidqqmail:Push

DALVIK THREADS:
(mutexes: tll=0 tsl=0 tscl=0 ghl=0)

"main" prio=5 tid=1 MONITOR
  | group="main" sCount=1 dsCount=0 obj=0x41e42b50 self=0x41e321f0
  | sysTid=9644 nice=0 sched=0/0 cgrp=apps handle=1074578908
  | state=S schedstat=( 211181635 61197479253 655 ) utm=13 stm=8 core=0
  at com.tencent.qqmail.utilities.qmnetwork.service.QMPushService.onStartCommand(SourceFile:~288)
  - waiting to lock <0x421809c0> (a com.tencent.qqmail.utilities.qmnetwork.service.QMPushService) held by tid=15 (Thread-2740)
  at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:2679)
  at android.app.ActivityThread.access$1900(ActivityThread.java:149)
  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1343)
  at android.os.Handler.dispatchMessage(Handler.java:99)
  at android.os.Looper.loop(Looper.java:213)
  at android.app.ActivityThread.main(ActivityThread.java:5092)
  at java.lang.reflect.Method.invokeNative(Native Method)
  at java.lang.reflect.Method.invoke(Method.java:511)
  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:797)
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:564)
  at dalvik.system.NativeStart.main(Native Method)

"Timer-0" daemon prio=5 tid=23 TIMED_WAIT
  | group="main" sCount=1 dsCount=0 obj=0x42313248 self=0x72be2018
  | sysTid=9693 nice=0 sched=0/0 cgrp=apps handle=1074262912
  | state=S schedstat=( 178436271 61426971433 856 ) utm=7 stm=10 core=0
  at java.lang.Object.wait(Native Method)
  - waiting on <0x42313248> (a java.util.Timer$TimerImpl)
  at java.lang.Object.wait(Object.java:401)
  at java.util.Timer$TimerImpl.run(Timer.java:238)

"QMThreadPool #3" daemon prio=3 tid=22 WAIT
  | group="main" sCount=1 dsCount=0 obj=0x42310418 self=0x700656f8
  | sysTid=9692 nice=13 sched=0/0 cgrp=apps/bg_non_interactive handle=1924222744
  | state=S schedstat=( 25787332 62892517091 453 ) utm=0 stm=2 core=0
  at java.lang.Object.wait(Native Method)
  - waiting on <0x42310538> (a java.lang.VMThread) held by tid=22 (QMThreadPool #3)
  at java.lang.Thread.parkFor(Thread.java:1231)
  at sun.misc.Unsafe.park(Unsafe.java:323)
  at java.util.concurrent.locks.LockSupport.park(LockSupport.java:159)
  at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2019)
  at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:413)
  at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1013)
  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1073)
  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
  at java.lang.Thread.run(Thread.java:856)
"WifiManager" prio=5 tid=20 NATIVE
  | group="main" sCount=1 dsCount=0 obj=0x42213ba0 self=0x7363b008
  | sysTid=9686 nice=0 sched=0/0 cgrp=apps handle=1923316488
  | state=S schedstat=( 41564937 61108032226 478 ) utm=1 stm=3 core=0
  #00  pc 00017fe8  /system/lib/libc.so (epoll_wait+12)
  #01  pc 00014b29  /system/lib/libutils.so (android::Looper::pollInner(int)+96)
  #02  pc 00014d91  /system/lib/libutils.so (android::Looper::pollOnce(int, int*, int*, void**)+104)
  #03  pc 0006725b  /system/lib/libandroid_runtime.so (android::NativeMessageQueue::pollOnce(_JNIEnv*, int)+22)
  #04  pc 00020050  /system/lib/libdvm.so (dvmPlatformInvoke+112)
  #05  pc 0004f8d1  /system/lib/libdvm.so (dvmCallJNIMethod(unsigned int const*, JValue*, Method const*, Thread*)+396)
  #06  pc 000294e0  /system/lib/libdvm.so
  #07  pc 0002d7a0  /system/lib/libdvm.so (dvmInterpret(Thread*, Method const*, JValue*)+184)
  #08  pc 000620ed  /system/lib/libdvm.so (dvmCallMethodV(Thread*, Method const*, Object*, bool, JValue*, std::__va_list)+272)
  #09  pc 00062117  /system/lib/libdvm.so (dvmCallMethod(Thread*, Method const*, Object*, JValue*, ...)+20)
  #10  pc 00056c8f  /system/lib/libdvm.so
  #11  pc 0000e4b8  /system/lib/libc.so (__thread_entry+72)
  #12  pc 0000dba4  /system/lib/libc.so (pthread_create+160)
  at android.os.MessageQueue.nativePollOnce(Native Method)
  at android.os.MessageQueue.next(MessageQueue.java:125)
  at android.os.Looper.loop(Looper.java:197)
  at android.os.HandlerThread.run(HandlerThread.java:60)
"Signal Catcher" daemon prio=5 tid=3 RUNNABLE
  | group="system" sCount=0 dsCount=0 obj=0x4211bac8 self=0x7306f9e8
  | sysTid=9649 nice=0 sched=0/0 cgrp=apps handle=1074354432
  | state=R schedstat=( 35980238 61091796864 464 ) utm=0 stm=3 core=0
  at dalvik.system.NativeStart.run(Native Method)

这里的MONITOR,NATIVE等线程状态很是让我们迷惑, 因为我们学习到的java thread的6种线程状态并不包含它们.
java的6种线程状态定义在/java/lang/Thread.java中:

//Thread.java
public class Thread implements Runnable {
    ...
    public enum State {
        /**
         * The thread has been created, but has never been started.
         */
        NEW,
        /**
         * The thread may be run.
         */
        RUNNABLE,
        /**
         * The thread is blocked and waiting for a lock.
         */
        BLOCKED,
        /**
         * The thread is waiting.
         */
        WAITING,
        /**
         * The thread is waiting for a specified amount of time.
         */
        TIMED_WAITING,
        /**
         * The thread has been terminated.
         */
        TERMINATED
    }
    ...
}

我们却发现这里的MONITOR并不在这6种状态中, 那么MONITOR到底代表的是什么意思呢? 就需要我们深入源码去找答案了.

"main" prio=5 tid=1 MONITOR

在VMThread.java中, 可以看到下面的代码, native thread有10种状态, 对应着java thread的6种状态.

//VMThread.java
    /**
     * Holds a mapping from native Thread statuses to Java one. Required for
     * translating back the result of getStatus().
     */
    static final Thread.State[] STATE_MAP = new Thread.State[] {
        Thread.State.TERMINATED,     // ZOMBIE
        Thread.State.RUNNABLE,       // RUNNING
        Thread.State.TIMED_WAITING,  // TIMED_WAIT
        Thread.State.BLOCKED,        // MONITOR
        Thread.State.WAITING,        // WAIT
        Thread.State.NEW,            // INITIALIZING
        Thread.State.NEW,            // STARTING
        Thread.State.RUNNABLE,       // NATIVE
        Thread.State.WAITING,        // VMWAIT
        Thread.State.RUNNABLE        // SUSPENDED
    };

这段代码就给出了答案, traces.txt文件中的MONITOR状态就对应着java的BLOCKED状态, 也就是"The thread is blocked and waiting for a lock."
在之前的文章中, 已经分析了android thread的底层实现其实就是linux下的pthread.
我们再看一下native层的Thread.cpp, 有这段代码:
http://osxr.org/android/source/dalvik/vm/Thread.cpp

const char* dvmGetThreadStatusStr(ThreadStatus status)
{
    switch (status) {
        case THREAD_ZOMBIE:         return "ZOMBIE";
        case THREAD_RUNNING:        return "RUNNABLE";
        case THREAD_TIMED_WAIT:     return "TIMED_WAIT";
        case THREAD_MONITOR:        return "MONITOR";
        case THREAD_WAIT:           return "WAIT";
        case THREAD_INITIALIZING:   return "INITIALIZING";
        case THREAD_STARTING:       return "STARTING";
        case THREAD_NATIVE:         return "NATIVE";
        case THREAD_VMWAIT:         return "VMWAIT";
        case THREAD_SUSPENDED:      return "SUSPENDED";
        default:                    return "UNKNOWN";
    }
}

实际上, 写入traces.txt中的线程状态值就是这个函数返回的字符串.
所以我们就知道了如下的事实:

"main" prio=5 tid=1 MONITOR  其实就是java中的BLOCKED状态.
"Timer-0" daemon prio=5 tid=23 TIMED_WAIT 其实就是java中的TIMED_WAITING状态
"QMThreadPool #3" daemon prio=3 tid=22 WAIT 其实就是java中的WAITING状态
"WifiManager" prio=5 tid=20 NATIVE 其实就是java中的RUNNABLE状态
"Signal Catcher" daemon prio=5 tid=3 RUNNABLE 其实就是java中的RUNNABLE状态

到这里, 我们也同样理解了DDMS中各个线程状态的含义.

thread_state_in_ddms.png

refer :
https://docs.oracle.com/javase/7/docs/api/java/lang/Thread.State.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,524评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,869评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,813评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,210评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,085评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,117评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,533评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,219评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,487评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,582评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,362评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,218评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,589评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,899评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,176评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,503评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,707评论 2 335

推荐阅读更多精彩内容