对于线程Thread类的使用,可以说是java语言必备,但你是否真正意义上去剖析过他的内部结构,本文从概述的几个问题出发,一起进行源码阅读(本文基于Android-27中的Thread源码)
对常用的Thread做一次源码剖析,更好的去理解和使用它,看完之后你会明白的几个问题:
Thread构造函数
内部调用—>init()方法
java.lang.Thread#Thread()
java.lang.Thread#Thread(java.lang.Runnable)
java.lang.Thread#Thread(java.lang.ThreadGroup, java.lang.Runnable)
java.lang.Thread#Thread(java.lang.String)
java.lang.Thread#Thread(java.lang.ThreadGroup, java.lang.String)
java.lang.Thread#Thread(java.lang.ThreadGroup, java.lang.String, int, boolean)
java.lang.Thread#Thread(java.lang.Runnable, java.lang.String)
java.lang.Thread#Thread(java.lang.ThreadGroup, java.lang.Runnable, java.lang.String)
java.lang.Thread#Thread(java.lang.ThreadGroup, java.lang.Runnable, java.lang.String, long)
init()方法指定四个参数:ThreadGroup,任务runable,线程名称,栈大小,其中部分参数初始值都是继承父线程的属性
private void init(ThreadGroup g, Runnable target, String name, long stackSize) {
Thread parent = currentThread();//获取创建thread的线程
if (g == null) {
g = parent.getThreadGroup();
}
g.addUnstarted();//在ThreadGroup中标记增加了一个未启动的线程,里面操作很简单,nUnstartedThreads++;
this.group = g;
this.target = target;
this.priority = parent.getPriority();//继承父线程的等级
this.daemon = parent.isDaemon();//继承父线程的属性:是否为守护进程
setName(name);
init2(parent);//保存一些常量参数,如上,给子线程调用
/* Stash the specified stack size in case the VM cares */
this.stackSize = stackSize;
tid = nextThreadID();
}
...
//线程 tid递增一个
private static synchronized long nextThreadID() {
return ++threadSeqNumber;
}
在Android中,检测到再次调用start线程会抛出IllegalThreadStateException
public synchronized void start() {
// Android-changed: throw if 'started' is true
if (threadStatus != 0 || started)
throw new IllegalThreadStateException();
//还记得上面init方法中,调用addUnstarted时,标记增加了未启动线程
//这里调用add方法,将线程添加到系统线程数组,并且将未启动线程数减一,相当于移出
group.add(this);
started = false;
try {
nativeCreate(this, stackSize, daemon);
//调用native方法启动线程,如果报错,则直接跳到finally执行,started为false,
//启动失败,从group中移除,同时group中未启动线程数++
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 */
}
}
}
//Thread实现的Runnable接口
class Thread implements Runnable {
...
//调用传入的Runnable的run方法
@Override
public void run() {
if (target != null) {
target.run();
}
}
join方法用于等待线程执行完成,传入的时间单位为等待的最大时长,里面是一个 while (isAlive())循环函数,当不传入时间参数,则为永久等待直到线程结束,传入时间参数,当时间到达时会结束join方法
public final void join(long millis) throws InterruptedException {
synchronized(lock) {
long base = System.currentTimeMillis();
long now = 0;
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (millis == 0) {
while (isAlive()) {
lock.wait(0);
}
} else {
//循环,当达到最大等待时常,则跳出循环
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
lock.wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
}
public final void join() throws InterruptedException {
join(0);
}
//等待多少毫秒在加多少纳秒
public final void join(long millis, int nanos)
throws InterruptedException {
synchronized(lock) {
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);
}
}
sleep作用是使当前线程睡眠指定时间,其中几个关键点
获取当前调用线程的lock:currentThread().lock;
通过while (true)循环sleep当前线程,并检测睡眠时间达到传输参数时间,break当前循环
public static void sleep(long millis, int nanos)throws InterruptedException {
if (millis < 0) {
throw new IllegalArgumentException("millis < 0: " + millis);
}
if (nanos < 0) {
throw new IllegalArgumentException("nanos < 0: " + nanos);
}
if (nanos > 999999) {
throw new IllegalArgumentException("nanos > 999999: " + nanos);
}
//当睡眠时间为0,先检测线程是否已经中断,是的话抛出异常,否则直接return
if (millis == 0 && nanos == 0) {
// ...but we still have to handle being interrupted.
if (Thread.interrupted()) {
throw new InterruptedException();
}
return;
}
long start = System.nanoTime();
long duration = (millis * NANOS_PER_MILLI) + nanos;
获取当前线程的lock
Object lock = currentThread().lock;
// Wait may return early, so loop until sleep duration passes.
synchronized (lock) {
while (true) {
sleep(lock, millis, nanos);
long now = System.nanoTime();
long elapsed = now - start;
if (elapsed >= duration) {
break;
}
duration -= elapsed;
start = now;
millis = duration / NANOS_PER_MILLI;
nanos = (int) (duration % NANOS_PER_MILLI);
}
}
}
public static void sleep(long millis) throws InterruptedException {
Thread.sleep(millis, 0);
}
@FastNative
private static native void sleep(Object lock, long millis, int nanos)
throws InterruptedException;
stop方法以及被弃用,强行调用的话会抛出UnsupportedOperationException异常
@Deprecated
public final void stop() {
stop(new ThreadDeath());
}
@Deprecated
public final void stop(Throwable obj) {
throw new UnsupportedOperationException();
}
部分内容引用一篇很详细的文章,戳–>《Java线程源码解析之interrupt》
interrupt的作用是中断线程,我们经常调用,interrupt的使用有几个注意点
当线程处于wait,sleep,join等方法阻塞状态时,它会清除当前阻塞状态,并抛出InterruptedException异常
在I/O通讯状态中调用interrupt,数据通道会被关闭,并将线程状态标记为中断,并抛出ClosedByInterruptException异常
如果在java.nio.channels.Selector上堵塞,会标记中断状态,并马上返回select方法
Lock.lock()方法不会响应中断,Lock.lockInterruptibly()方法则会响应中断并抛出异常,区别在于park()等待被唤醒时lock会继续执行park()来等待锁,而 lockInterruptibly会抛出异常
synchronized被唤醒后会尝试获取锁,失败则会通过循环继续park()等待,因此实际上是不会被interrupt()中断的;
一般情况下,抛出异常时,会清空Thread的interrupt状态,在编程时需要注意;
//用来中断的IO通讯对象,在调用interrupt方法后会调用blocker的中断方法
private volatile Interruptible blocker;
public void interrupt() {
if (this != Thread.currentThread())
checkAccess();
synchronized (blockerLock) {
Interruptible b = blocker;
if (b != null) {
nativeInterrupt();
b.interrupt(this);
return;
}
}
nativeInterrupt();
}
public enum State {
NEW,
RUNNABLE,
BLOCKED,
WAITING,
TIMED_WAITING,
TERMINATED;
}
public State getState() {
// get current thread state
return State.values()[nativeGetStatus(started)];
}
if (threadStatus != 0 || started)
,如果已经启动则抛出IllegalThreadStateException异常,可以通过继承Thread类或者实现Runnable去开启线程,这样每次new了新的对象启动线程