专业的JAVA编程教程与资源

网站首页 > java教程 正文

Java 线程的生命周期及状态详解

temp10 2024-12-12 15:07:51 java教程 11 ℃ 0 评论

新建(New)状态

  • 创建线程对象:当在 Java 程序中通过new关键字创建一个线程对象时,线程就进入了新建状态。例如,Thread thread = new Thread();语句创建了一个Thread类的实例,此时这个线程就处于新建状态。这个状态下的线程仅仅是一个 Java 对象,还没有开始执行。它已经被分配了内存空间,并且其成员变量也被初始化,但是线程的执行逻辑还没有开始运行。
  • 尚未分配系统资源:在新建状态下,线程还没有被操作系统分配执行所需的系统资源,如 CPU 时间片等。它只是在 Java 虚拟机的内存中有了一个代表自身的对象,等待被启动。

就绪(Runnable)状态

  • 启动线程后的状态转换:当调用线程对象的start()方法后,线程就从新建状态转换到就绪状态。这里的就绪状态是一个统称,它实际上包含了两种子状态:Ready 状态和 Running 状态(Running 状态可以看作是就绪状态下正在执行的瞬间状态)。例如,在前面创建的thread对象上调用thread.start();方法,线程就会进入就绪状态,此时它可能处于 Ready 子状态,等待 CPU 分配时间片来真正执行,一旦获得时间片就进入 Running 子状态。
  • 就绪状态的线程队列:在多线程环境下,可能有多个线程处于就绪状态(包含 Ready 和可能正在 Running 的情况)。这些线程会被放入一个就绪队列中,等待 CPU 的调度。操作系统会根据一定的调度算法(如时间片轮转、优先级调度等)从就绪队列中选择一个线程来执行。例如,在一个简单的时间片轮转调度算法中,每个线程会被分配一个固定的时间片来执行任务,当时间片用完后,线程会重新回到就绪队列的 Ready 子状态,等待下一次调度。
  • 可能的状态切换及方法调用
  • 转换到 Running 状态:这是由操作系统的调度器来决定的,不需要程序员显式调用方法。当操作系统根据其调度算法选择该就绪状态的线程并分配 CPU 时间片时,线程就从 Ready 子状态进入 Running 状态。
  • 转换到阻塞状态
  • 等待锁阻塞:当多个线程竞争同步锁时,若线程尝试获取一个已经被其他线程持有的锁,就会进入阻塞状态。在 Java 中,通过synchronized关键字来实现锁机制。例如,在一个共享资源(如一个共享的队列)被synchronized修饰的方法或代码块中,当一个线程正在执行这个方法或代码块时(处于 Running 状态),其他线程尝试访问就会等待锁的释放而阻塞,从 Ready 子状态或 Running 状态进入阻塞状态。
  • 等待 I/O 阻塞:当线程执行 I/O 操作(如读取文件、网络通信等)时会阻塞。在 Java 中,通过InputStream、OutputStream等类的方法(如read()、write()方法)来进行 I/O 操作,当调用这些方法开始 I/O 操作后,线程就会从 Ready 子状态或 Running 状态进入阻塞状态,直到 I/O 操作完成。
  • 等待唤醒阻塞:线程可以通过调用Object类的wait()方法来等待其他线程的通知而进入阻塞状态。例如,在生产者 - 消费者模型中,消费者线程在缓冲区为空时可以调用wait()方法等待生产者生产数据,此时不管是处于 Ready 子状态还是 Running 状态都会进入阻塞状态。

运行(Running)状态

  • 获得 CPU 时间片开始执行:当就绪状态的线程被操作系统选中并分配到 CPU 时间片时,线程就进入了运行状态(更准确地说是从 Ready 子状态转换到 Running 状态)。在这个状态下,线程会执行其run()方法中的代码逻辑。例如,如果线程的任务是打印从 1 到 10 的数字,那么在 Running 状态下,它会依次执行打印操作。线程在 Running 状态下可以访问和修改共享数据(如果存在共享资源的情况),并且可以和其他线程进行交互,如通过共享对象的方法调用或者等待其他线程的通知。
  • 可能的状态转换及方法调用
  • 转换到就绪状态(Ready 子状态):当线程的时间片用完或者被具有更高优先级的线程抢占 CPU 资源时,会从 Running 状态重新回到就绪状态的 Ready 子状态。这是由操作系统调度器自动完成的,不需要显式调用方法。
  • 转换到阻塞状态
  • 调用sleep()方法:线程可以通过调用Thread类的sleep(long millis)方法,使线程暂停执行指定的毫秒数,进入阻塞状态。例如,Thread.sleep(1000);会使线程从 Running 状态暂停 1 秒,在这期间线程处于阻塞状态。此时线程处于Time_Waiting(限时等待)状态,因为它会在指定的时间后自动恢复到就绪状态的 Ready 子状态。
  • 调用wait()方法:线程在获取了一个对象的锁后,可以调用该对象的wait()方法来释放锁并进入阻塞状态,等待其他线程调用notify()或notifyAll()方法来唤醒。例如,在一个同步块中,synchronized (obj) {obj.wait();}会使线程从 Running 状态进入阻塞状态,此时线程处于Waiting(无限等待)状态,因为它会一直等待,直到被其他线程唤醒,唤醒后回到就绪状态的 Ready 子状态。
  • 等待同步锁阻塞:如果线程在 Running 状态过程中尝试获取一个被其他线程占用的同步锁,会从 Running 状态进入阻塞状态。这是通过 Java 的同步机制(如synchronized关键字)自动实现的,不需要额外的方法调用。

阻塞(Blocked)状态

  • 等待资源或事件而暂停执行:线程在运行过程中可能会因为等待某些资源或者事件而进入阻塞状态。例如,当一个线程试图获取一个被其他线程占用的同步锁时,它会被阻塞。另外,当线程调用Object类的wait()方法时,它会释放持有的锁并且进入阻塞状态,直到被其他线程通过notify()或notifyAll()方法唤醒。例如,在生产者 - 消费者模型中,消费者线程在缓冲区为空时可能会调用wait()方法等待生产者生产数据,此时消费者线程就进入了阻塞状态。
  • 阻塞状态的多种情况
  • 等待锁阻塞:这种情况是由于多个线程竞争同步锁导致的。当一个线程尝试获取一个已经被其他线程持有的锁时,它会进入阻塞状态,等待锁的释放。例如,在一个多线程访问共享资源(如一个共享的队列)的场景中,为了保证数据的一致性,会使用synchronized关键字来保护对队列的操作。当一个线程正在对队列进行操作(持有锁)时,其他试图访问队列的线程就会等待锁的释放而进入阻塞状态。
  • 等待 I/O 阻塞:当线程执行 I/O 操作(如读取文件、网络通信等)时,由于 I/O 操作的速度通常比 CPU 和内存操作慢很多,线程会被阻塞,直到 I/O 操作完成。例如,当一个线程读取一个大型文件时,在文件读取操作完成之前,线程会处于阻塞状态,等待数据从磁盘加载到内存。
  • 等待唤醒阻塞:如前面提到的通过wait()方法等待被唤醒的情况。这种阻塞通常用于线程之间的协作,一个线程等待另一个线程完成某些操作或者发送某个信号后再继续执行。
  • 可能的状态切换及方法调用
  • 转换到就绪状态(Ready 子状态)
  • 等待锁阻塞后获取锁:当阻塞是因为等待锁而引起的,当其他线程释放锁后,该线程获取到锁就会从阻塞状态转换到就绪状态的 Ready 子状态,这个过程是由 Java 的同步机制自动完成的。
  • 等待 I/O 完成后:当线程因为 I/O 操作而阻塞,在 I/O 操作完成后会自动从阻塞状态转换到就绪状态的 Ready 子状态,等待 CPU 调度。
  • 被唤醒后:如果线程是因为调用wait()方法而阻塞,当其他线程调用notify()或notifyAll()方法唤醒它时,它会从阻塞状态转换到就绪状态的 Ready 子状态。例如,在一个对象上调用notify()方法可以唤醒在该对象上等待的一个线程,使它回到就绪状态的 Ready 子状态。
  • 转换到运行状态(Running 状态):当线程从阻塞状态转换到就绪状态(Ready 子状态)后,经过操作系统调度,就可以从就绪状态的 Ready 子状态转换到 Running 状态,这个过程不需要程序员显式调用方法。

死亡(Dead)状态

  • 线程任务执行完毕正常结束:当线程的run()方法执行完毕,或者线程因为异常而终止时,线程就进入了死亡状态。例如,一个简单的线程任务是计算 1 到 100 的累加和,当累加和计算完成后,线程的run()方法结束,线程就死亡了。在这个状态下,线程已经结束了其生命周期,不再占用系统资源(除了线程对象本身占用的少量内存,等待垃圾回收)。
  • 无法再次启动已死亡的线程:需要注意的是,一旦线程进入死亡状态,就不能再通过start()方法来重新启动它。如果尝试重新启动一个已经死亡的线程,会抛出IllegalThreadStateException异常。这是因为线程的资源已经被释放,再次启动可能会导致不可预测的行为。

理解 Java 线程的生命周期及其状态转换对于编写正确、高效的多线程程序非常重要。在实际开发中,需要根据不同的业务需求合理地处理线程的状态,以确保程序的正确性和性能。

Java 线程的生命周期及状态详解

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表