线程的生命周期
线程的生命周期:新建(NEW),就绪(Runnable),运行(Running),阻塞(Blocked),死亡(Dead)5种状态。
新建和就绪
当使用 new关键字创建一个线程时,线程处于新建状态。Java虚拟机为其分配内存。并初始化其成员变量的值。
当线程对象调用 start()方法后,线程处于就绪状态。Java虚拟机为其创建方法调用栈和程序计数器。
只能对处于新建状态的线程调用 start() 方法。否则会引发 IllegalThreadStateException。
运行和阻塞状态
如果处于就绪状态的线程获得CPU,开始执行run() 方法,则线程处于运行状态。
线程运行过程中会被中断, 目的是使其他线程获得执行机会。
失去处理资源的线程进入就绪状态, 获得处理资源的线程会由就绪进入运行状态。
调用 yield() 方法可以让运行状态进入就绪状态。
发生下面情况时:进入阻塞状态
- 线程调用sleep()
- 调用一个阻塞时IO方法, 在该方法返回之前,该线程会被阻塞
- 获得一个同步监视器,该监视器正被其他线程所持有
- 等待某个通知notify
- 调用 suspend()挂起
被阻塞后,其他线程获得执行的机会。
上面被阻塞的线程, 下面情况时,会重新进入就绪状态: - sleep() 时间过了
- 阻塞式IO已返回
- 获得了同步监视器
- 等待通知时, 其他线程发出来一个通知
- 处于挂起状态的线程,调用了 resume()
线程死亡
线程会以以下三种方式结束,结束后处于死亡状态
- run() 或 call()方法执行完
- 抛出一个未捕获的Exception或 Error
- 调用线程的 stop() 方法, 易导致死锁
可以通过 isAlive() 方法判断是否死亡: 就绪,运行,阻塞时返回TRUE, 新建和死亡时返回false。
处于死亡状态的线程无法再次运行。
控制线程
join线程
当在程序执行中调用其他线程的 join()方法时,调用线程会被阻塞,直到被join()方法加入的join线程执行完为止。
public class FirstThread extends Thread {
public FirstThread(String name){
super(name);
}
public void run(){
for (int i = 0; i < 100; i++){
System.out.println(getName() + " " + i);
}
}
public static void main(String[] args) throws Exception{
new FirstThread("新线程").start();
for(int i = 0; i < 100; i++){
if(i == 20){
FirstThread firstThread = new FirstThread("join 线程");
firstThread.start();
firstThread.join();
}
System.out.println(Thread.currentThread().getName() + " " + i);
}
}
}
//Output
...
join 线程 96
join 线程 97
join 线程 98
join 线程 99
main 20
main 21
main 22
main 23
main 24
...
"join 线程"执行完后, 主线程才会继续执行。
join(long millis) 可以设置join线程的等待最长时间,如果该时间内还没有执行结束,则不再等待。
后台线程
后台线程 Daemon Thread, 也称为守护线程。
前台线程死亡时,后台线程会自动死亡。
调用线程对象的 setDaemon(true)设置为后台线程。
isDaemon() 可以判断
public class FirstThread extends Thread {
public void run(){
for (int i = 0; i < 1000; i++){
System.out.println(getName() + " " + i);
}
}
public static void main(String[] args){
FirstThread firstThread = new FirstThread();
firstThread.setDaemon(true);
firstThread.start();
for(int i = 0; i < 10; i++){
System.out.println(Thread.currentThread().getName() + " " + i);
}
}
}
//Output
...
Thread-0 112
Thread-0 113
Thread-0 114
Thread-0 115
Thread-0 116
后台线程并没有执行完,前台退出后后台线程也结束了。
前台线程创建的子线程默认是前台线程, 后台线程创建的子线程,默认是后台线程
sleep()
sleep() 让线程暂停一段时间, 进入阻塞状态。
Thread.sleep(1000)
暂停1000 ms。
yield()
yield()是Thread类提供的一个静态方法。 让线程暂停,但不会进入阻塞状态,只是将线程转入就绪状态,
当某个线程调用yield时, 只有优先级大于等于当前线程的,处于就绪状态的线程执行。
可以通过 setPriority()设置优先级, 参数为 0- 10 之内的整数。
- MAX_PRIORITY : 10
- MIN_PRIORITY : 1
- NORM_PRIORITY: 5
public class FirstThread extends Thread {
public FirstThread(String name){
super(name);
}
public void run(){
for (int i = 0; i < 50; i++){
System.out.println(getName() + " " + i);
if(i == 20){
Thread.yield();
}
}
}
public static void main(String[] args){
FirstThread t1 = new FirstThread("HIGH");
t1.setPriority(Thread.MAX_PRIORITY);
t1.start();
FirstThread t2 = new FirstThread("LOW");
t2.setPriority(Thread.MIN_PRIORITY);
t2.start();
}
}
//Output
...
LOW 18
LOW 19
LOW 20
HIGH 21
HIGH 22
HIGH 23
HIGH 24
HIGH 25
HIGH 26
...