Thread源码
1. Thread类API
1.1 设置线程名
public class Thread implements Runnable {
//默认使用的线程名是“Thread-X”
public Thread() {
init(null, null, "Thread-" + nextThreadNum(), 0);
}
public final synchronized void setName(String name) {
checkAccess();
if (name == null) {
throw new NullPointerException("name cannot be null");
}
this.name = name;
if (threadStatus != 0) {
setNativeName(name);
}
}
}
1.2 守护线程
守护线程是为其他线程服务的:
- 垃圾回收线程就是守护线程
守护线程有一个特点:
- 当别的用户线程执行完了,虚拟机就会退出,守护线程也就会被停止掉了
- 守护线程做为一个服务线程,为由服务对象就没有必要继续运行了
守护线程注意事项:
-
在线程启动之前设置为守护线程,方法是setDaemon(boolean on)
如果启动之后再设置会抛出异常
-
使用守护线程不要访问共享资源 (数据库、文件等),因为它可能会在任何时候就挂掉了
-
守护线程中产生的新线程也是守护线程
1.3 优先级线程
线程优先级高仅仅表示线程获取的CPU时间片的几率高,但这不是一个确定的因素。
线程的优先级是高度依赖于操作系统的,Windows和Linux有区别。Linux下优先级会被忽略
Java默认提供的优先级是5,最低是1,最高是10
设置线程优先级时,如果存在线程组,那么该线程的优先级不能高于线程组的优先级。设置了高于线程组的优先级时,会自动的设置为和线程组优先级相同。
setPriority()
:设置线程优先级
1.4 线程生命周期
线程有3个基本状态:执行、就绪、阻塞
Thread中,有很多方法是用来切换线程状态的。
-
sleep方法
调用sleep方法会进入阻塞状态,等时间到了,进入的是就绪状态而非是运行状态。
-
yield方法 (不常用)
调用yield方法会先让别的线程执行,但是不确保真正让出
-
join方法
调用join方法,会等待被join线程执行完毕后才执行别的线程
如:在B线程中,执行A.join,此时B线程会进入阻塞状态(循环调用wait方法),开始执行A,等A执行完,再执行B线程(notify唤醒)。
-
interrupt方法
在之前的jdk版本中,存在Thread.stop方法,但是被设置为过时了。现在已经没有强制线程终止的方法了。
stop强制线程终止的策略太暴力且不安全,因此被过时
在现在的版本中,一般使用Interrupt来请求终止线程:
- Interrupt不会真正停止一个线程,它不仅仅是给这个线程发了一个信号告诉他,它应该要结束了。
- Java设计者实际上是想让线程自己来进行终止,通过Interrupt发出的信号,可以判断是否需要进行终止业务。
- 具体进行中断还是继续执行,由被通知的线程自己决定。
public void interrupt() { if (this != Thread.currentThread()) checkAccess(); //使用了闭锁 synchronized (blockerLock) { Interruptible b = blocker; if (b != null) { //只将线程中的Interrupt标记置为true interrupt0(); b.interrupt(this); return; } } interrupt0(); }
调用Interrupt并不是真正要终止掉当前线程,仅仅是设置了一个中断标志。这个标志用来判断当前线程的状态,什么时候中断由线程内部决定,这样就可以安全地终止线程了。
Interrupt方法是不会对线程的状态造成影响的,它仅仅设置一个标志位。
Interrupt线程中断还有两个方法:
- 静态方法 interrupted() --> 清除中断标志位
- 实例方法 isInterrupted() --> 不会清楚中断标志位
如果阻塞线程调用了interrupt()方法,那么会抛出异常,设置标志位为false,同时该线程会退出阻塞的。