线程生命周期
线程是有生命周期的,包括了线程从出现、执行到最终结束消亡时的各种状态。一个线程从被创建开始,其生命周期总共分为五个阶段:
1.创建状态
- 线程被创建时(使用new和Thread创建线程对象),系统会分配资源并初始化该线程。这只是一个暂态,会一直保持到调用start0方法、线程进人运行或阻塞阶段之前。
2.就绪状态
- 对一个创建状态的线程调用了start0方法后,线程进人就绪状态。就绪状态的线程会处于队列中等待JVM调度,直到线程获取系统资源。
3.运行状态
- 处于就绪状态的线程获取系统内存资源时,会执行rm0方法,此时线程处于运行状态。处于运行状态的线程可以变成阻塞状态或死亡状态。
4.阻塞状态
- 如果一个线程执行了sleep0方法、suspend0方法或试图获取另一个已被其他线程占有的锁时,会暂时失去系统资源而进人阻塞状态。当设置的睡眠时间到期或获得系统资源后,线程可以重新进人就绪状态。
5.死亡
- 当线程执行完毕、发生异常或错误时,线程会终止并进人死亡阶段,这个阶段的线程是不可调度的,即不可再运行。
操作线程:
1.休眠线程
我们可以使用Thread类中的sleep()方法使一个线程进入休眠,即阻塞状态。该方法需要一个指定休眠时间的入参,单位为毫秒。sleep()的调用方法如下:
Thread.sleep(1000)
上述代码会让线程在1秒内不会进入就绪状态。在使用时,由于sleep()方法可能会抛出异常,需要使用try catch关键字来捕获异常,避免程序的意外中断。需要注意的是,sleep()方法设置的休眠时间到期后,线程并不会马上进入运行状态,而是进入就绪状态等待JVM调度。
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
2.中断线程
Thread类中的stop()方法已被废弃,目前中断线程的方法是在run()方法中使用循环语句。通过条件语句进行判断,当满足某一条件时跳出循环, 使线程在执行完run()代码块后自动中断。
3.线程的暂停与恢复
- void wait (long timeout) 在其他线程调用此对象的 notify () 方法或 notifyAll ()方法,或者超过指定的时间量前,导致当前线程等待。
- void notify () 唤醒在此对象监视器上等待的单个线程,随机唤醒。
- void notifyAll () 唤醒在此对象监视器上等待的所有线程。
sleep() 和 wait() 方法的区别:
共同点:可以使线程处于一种阻塞状态,如果是休眠使用void interrupt()清除阻塞。 如果是等待,那就使用notify()
不同点:
-
sleep() 线程一旦休眠不释放锁。wait() 线程一旦等待,就会释放锁。
-
sleep()方法,必须设置休眠时间。wait()方法可以设置等待时间也可以不设置。
死锁
一个对象可以使用synchronized方法或其他形式的加锁机制,让任务进入阻塞状态,此时会出现-种情况:一个任务在等待另一个任务,后者又在等待别的任务,不断循环下去,直到这条链路上的任务又在等待第一个任务释放锁。这时所有线程任务都无法继续执行,全都在等待任务解锁中不断地循环下去,令程序进人死循环,也就是死锁。
package demo3;
//死锁
public class MyThread extends Thread{
public static final Object objA=new Object();
public static final Object objB=new Object();
private boolean flag;
public MyThread(boolean flag){
this.flag = flag;
}
public void run() {
if (flag) {
synchronized (objA) {
System.out.println("true进程持有objA锁");
synchronized (objB){
System.out.println("true进程持有objB锁");
}
}
}else {
synchronized (objB) {
System.out.println("false进程持有objB锁");
synchronized (objA) {
System.out.println("false进程持有objA锁");
}
}
}
}
}
多线程的匿名类
package demo2;
//匿名类
public class Test4 {
public static void main(String[] args) {
new Thread(){
public void run() {
System.out.println("执行了。。。。");
}
}.start();
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("hhhhhhhhhhhhhhhhh");
}
}).start();
}
}
运行结果:
执行了。。。。
hhhhhhhhhhhhhhhhh