JAVA和Nginx 教程大全

网站首页 > 精选教程 正文

为什么Java中线程没有Running状态

wys521 2024-11-18 18:01:48 精选教程 23 ℃ 0 评论

Java线程的状态

1:初始线程,也就是new Thread,但是还没有调用start方法,还在JVM堆中,没有和OS真正的线程挂钩。

2:运行(RUNNABLE):调用了start,这时候os才会真正创建线程并和我们JVM堆中的线程挂钩,os创建完线程后,需要等待cpu调度,cpu还没轮到在os层面是就绪状态(ready),cpu轮到了就是运行中(running)这两种状态,在java层面统称为运行状态。

3:阻塞(BLOCKED):调用synchronized关键字。

4:等待(WAITING):比如调用了wait,join,park等等需要被唤醒。

5:超时等待(TIMED_WAITING):该状态不同于WAITING,它可以自己执行时间比如sleep(long),wait(long).... .... 。

6:中止:线程执行完成。

线程从创建到销毁都有哪些步骤

在操作系统层面,一个线程从创建到销毁大致经历以下步骤:

  1. 创建:当一个线程被创建时,操作系统会为它分配必要的资源,例如内存、寄存器等。此时,线程处于新建状态。
  2. 调度:操作系统的调度器会根据调度算法选择一个就绪状态的线程来运行。当一个线程被调度器选中后,它会获得CPU时间片,进入运行状态。
  3. 上下文切换:当一个正在运行的线程因为某些原因(例如时间片用完、等待I/O操作等)无法继续运行时,操作系统会将它切换出CPU,让其他线程来运行。在进行上下文切换时,操作系统会保存当前线程的上下文(例如寄存器值、程序计数器值等),以便在下一次调度这个线程时能够恢复它的运行状态。
  4. 挂起:有时候,一个线程可能需要等待某些事件(例如I/O操作完成、信号量可用等)才能继续运行。此时,操作系统会将这个线程挂起,让它进入阻塞状态。当等待的事件发生后,线程会重新进入就绪状态,等待被调度器选中运行。
  5. 销毁:当一个线程完成了它的任务或者被强制终止时,操作系统会回收它所占用的资源,并将其销毁。此时,线程的生命周期结束。

什么是线程的调度

线程调度是操作系统为线程分配CPU使用权的过程,决定了哪个线程会在何时运行。Java的线程调度是基于抢占式的,这意味着优先级更高的线程更可能被操作系统选中执行,但是它并不能保证一定会被执行。

线程调度主要有两种方式:

  1. 协同式线程调度(Cooperative Threads-Scheduling):在这种调度方式中,线程的执行时间由线程本身控制。线程会在完成其任务后,主动通知操作系统将控制权切换到另一个线程。协同式线程调度的主要优点是它的实现简单,因为线程在完成自己的任务后才通知系统进行线程切换,所以不存在线程同步的问题。然而,缺点也非常明显,如果一个线程出现问题,整个程序可能会阻塞。
  2. 抢占式线程调度(Preemptive Threads-Scheduling):在这种调度方式中,线程的执行时间以及是否需要切换由操作系统决定。这种情况下,线程的执行时间是不可控制的,这避免了“一个线程导致整个进程阻塞”的问题。Java线程调度就是基于抢占式的。有可能线程执行一会系统调度,然后就让另外一个线程执行了。

在Java中,虽然可以通过Thread.yield()方法让线程主动放弃当前分配的CPU时间,但线程无法控制自己何时获得CPU时间。

线程实现模型:内核线程,用户线程与混合实现

在我们的日常编程中,线程作为执行单位,常常被用来完成多任务的并行处理。然而,线程的底层实现模型却有多种,包括内核线程,用户线程,以及这两者的混合实现。它们各自的优缺点以及使用场景有所不同。

内核线程

内核线程(Kernel-Level Thread,KLT)是直接由操作系统内核支持和管理的线程。线程切换、调度以及任务的处理器映射,都由内核负责。每个内核线程都是一个独立的调度单元,所以即使某个线程在执行系统调用时被阻塞,也不会影响整个进程的执行。这种方式的优点是操作系统能够全面地掌控线程的生命周期,不会出现由于一个线程的问题影响整个进程的情况。然而,因为线程的创建、销毁和同步等操作都需要进行系统调用,而系统调用涉及到用户态和内核态的切换,所以这种方式的代价相对较高。

用户线程

用户线程,也就是在用户空间实现的线程,系统内核并不能感知到用户线程的存在以及其实现方式。用户线程的创建、销毁、切换和调度都在用户态完成,不需要内核的干预。因此,这种方式的操作可以非常快速且低消耗,并且能够支持大规模的线程数量。然而,用户线程的缺点在于,因为缺乏系统内核的支持,所有的线程操作都需要由用户程序自己去处理。例如,处理阻塞的问题、和实现上下文切换和抢占式调度,都会变得异常困难,甚至有些是无法实现的。

混合实现

混合实现模型将内核线程和用户线程结合起来使用,称为N:M实现。在这种模型中,既有用户线程也有内核线程。用户线程仍然在用户空间中创建,其创建、切换、销毁等操作仍然是廉价的,并且可以支持大规模的并发。同时,内核线程提供了线程调度和处理器映射的功能。在这种模式下,用户线程和内核线程的数量比是不定的,即N:M关系。

Java 线程的实现

Java线程的实现和系统内核线程是1:1关系,java线程的创建资源分配,以及上下文切换cpu调度都是由内核来完成的。java是不去干预的,这样实现的好处是简单。坏处就是浪费,举个例子,一个请求过来,可能也就几毫秒,但是java中就需要为一个单独的线程去处理浪费资源,除非是我们自己创建线程,自己调度,以及自己切换上下文。

为什么没有Running状态。

java线程和内核线程是1:1,是抢占式调度的。java线程调用start,进入RUNNABLE状态。os帮我们创建内核线程,进入就绪状态,等待cpu的调度。因为java线程是抢占式调度,完全不需要自己参与,什么时候从ready到running,又什么时候从running到ready,java是不知道的。

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

欢迎 发表评论:

最近发表
标签列表