线程生命周期

线程的五种状态:新建(New)、就绪(Ready)、运行(Running)、阻塞(Blocked)、死亡(Dead)

新建状态

  当创建一个Thread对象时,线程进入新建状态。此时线程还没有开始执行,但是它的相关资源已经被分配

1
2
3
4
5
6
7
8
public static void main(String[] args) {
Thread thread = new Thread() {
@Override
public void run() {
super.run();
}
};
}

就绪、运行状态

  调用线程的start()方法会使线程进入就绪状态。处于就绪状态的线程已经具备了执行条件,等待系统的调度器分配CPU时间片。
  当就绪状态的线程获得了CPU时间片,将开始执行run()方法中的代码,线程进入运行状态

1
2
3
4
5
6
7
8
9
public static void main(String[] args) {
Thread thread = new Thread() {
@Override
public void run() {
super.run();
}
};
thread.start();
}

阻塞状态

  在抢占式策略的系统中,线程开始执行后不会一直处于运行状态,因为CPU时间片同时也要分配给其他线程,所以当运行中的线程时间片用完时,将会进入阻塞状态。在多线程编程中,操作系统的调度器会负责分配CPU时间片给各个线程。每个线程在运行一段时间后,操作系统会将CPU时间片切换给其他就绪状态的线程,以实现多个线程之间的并发执行。因此,即使线程处于运行状态,它也会被操作系统调度器抢占,从而让其他线程有机会执行。

  此外,在发生如下情况时,线程将会进入阻塞状态

  1. 调用阻塞式IO操作:当线程执行阻塞式的输入/输出操作时,比如读取文件、网络通信等,线程会被阻塞,直到IO操作完成或超时。
  2. 调用sleep()方法:线程可以通过调用Thread.sleep(milliseconds)方法来主动暂停执行一段时间。在这段时间内,线程会进入阻塞状态。
  3. 等待获取锁:线程在并发编程中可能需要获取共享资源的锁。如果某个线程在执行过程中发现锁已经被其他线程占用,那么该线程会被阻塞,直到锁被释放。
  4. 等待条件的满足:线程在某些情况下需要等待特定的条件满足才能继续执行。通过调用wait()方法进入等待状态,并在其他线程中满足条件后通过notify()notifyAll()方法唤醒。
  5. 加入其他线程:通过调用Thread.join()方法,一个线程可以等待另一个线程执行完毕后再继续执行。在等待期间,线程会进入阻塞状态。

  当正在执行的线程被阻塞后,其他线程就可以获得执行的机会,阻塞解除后,线程将重新进入就绪状态

死亡状态

  以下三种情况,会导致线程死亡,死亡后的线程不可以再次通过调用start()启动,通过isAlive()方法,可以判断线程是否为死亡状态

  1. run()call()方法执行完成,线程正常结束
  2. 线程抛出一个未捕获的Exception或Error
  3. 调用该线程的stop()方法结束线程