本文主要分析Android平台上的Thread类源码,分为Java部分和native部分。
Java部分比较简单,大致过下各个方法吧。
线程创建
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
|
线程NEW
出来的时候只是从创建它的线程那里继承一些属性,比如threadgroup,daemon状态,priority,stacksize,inheritableThreadLocals之类的。真正启动线程是在start
方法里。
线程启动
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
|
一大堆代码只需要记住进行了pthread_create
系统调用即可。
线程状态
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
|
线程有6种状态,NEW
表示线程新建,还没调用start()
。RUNNABLE
表示线程调用了start
处于可运行状态,等待CPU调度。BLOCKED
表示线程在等待获取monitor lock。当在线程中调用Object.wait()
或Thread.join()
或LockSupport.park()
方法时线程进入WAITING
状态,在线程中调用Thread.sleep()
或Object.wait(long)
或Thread.join(long)
或LockSupport.parkNanos(long)
或LockSupport.parkUntil(long)
线程进入TIMED_WAITING
状态。线程执行完操作后会进入TERMINATED
状态。
线程中断
线程中一共有3个和中断有关的方法,分别是interrupt()
,isInterrupted()
和静态方法interrupted
。我们分别看一下。
interrupt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
|
从注释我们可以看出调用Thread的interrupt
方法,分为几种情况
- 如果线程阻塞在
Object.wait()
、Object.wait(long)
、Object.wait(long,int)
、Thread.join()
、Thread.join(long)
、Thread.join(long,int)
、Thread.sleep(long)
、Thread.sleep(long,int)
这些方法上,线程的中断状态将被清除,并抛出InterruptedException
。 - 如果阻塞在
java.nio.channels.InterruptibleChannel
IO操作操作上,线程的中断状态将被设置(这里有个疑惑,这里设置是指设置为true还是false,如果设置为false就表示线程状态被清除了,由于对NIO了解不多,这里暂时无法确定,从注释上下文理解应该是设置为true了)并抛出java.nio.channels.ClosedByInterruptException
- 如果阻塞在
java.nio.channels.Selector
上,线程的中断状态将被设置,并从Selector
操作中返回。 - 如果是其他情况,比如正在执行不会响应
interrupt
方法的方法(如Socket
的读写或ServerSocket
的accept
),那么线程的中断状态将被设置。
继续看nativeInterrupt
方法,从java_lang_thread.cc中Thread_nativeInterupt可以看到是调用了Thread::Interrupt。
1 2 3 4 5 6 7 8 9 |
|
可以看到只是设置了一下中断状态。
isInterrupted 和 interrupted
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
|
实例方法isInterrupted
会返回线程的中断状态,静态方法interrupted
会返回调用这个方法的线程的中断状态,并清除线程的中断状态,这也是清除中断状态的唯一方法,设置中断状态当然调用interrupt
方法就好了。
不妨看下native层实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
守护线程
线程可分为两种,普通线程和守护线程(其实叫服务线程好理解些,这些线程一般是服务其他线程的)。在JVM启动时创建的所有线程中,除了主线程以外,其他的线程都是守护线程(例如垃圾回收器以及执行其他辅助工作的线程,signal dispatcher之类的)。
当创建一个新线程时,新线程将继承创建它的线程的守护状态。
普通线程和守护线程之间的差异仅在于当线程退出时发生的操作。当一个线程退出时,JVM会检查其他正在运行的线程,如果这些线程都是守护线程,那么JVM会正常退出操作。当JVM停止时,所有仍然存在的守护线程都将被抛弃——既不会执行finally代码块,也不会执行回卷栈,而JVM只是直接退出。
reference
- 《Java并发编程实战》
- Android平台上除了Java线程还有native线程,可以参考这篇