Java线程调度

时间:2013-05-23 13:56:51

标签: java multithreading scheduling

我的笔记说有两种主要类别的线程调度算法,抢占式和时间共享。我想清楚一下这些在Java中是如何工作的。

据我所知(如果我有点错误,请纠正我!)preemptive允许更高优先级的线程在进入可运行状态时从较低优先级的线程接管CPU。它是否会垄断CPU直到更高优先级的线程出现,或者它是否会占用大部分CPU时间,但优先级较低的线程也会有机会运行?我在这里假设没有调用方法会放弃像yield()或sleep()那样的CPU。

在时间共享中,优先级较高的线程是否会获得更大的CPU时间份额?

我猜测我的解释(以及我提出的问题)对于先发制人是不对的,因为它只是看起来和时间分享一样!但我想确定细节。

我想,这一切是如何实现的? JVM或OS是否调度线程,还是JVM实现依赖?

4 个答案:

答案 0 :(得分:4)

首先,我怀疑你的笔记是不正确的,并且应该 -preemptive与时间共享(也称为抢先)。至少,这就是我几十年前参加OS课程时的故障情况,我怀疑它已经改变了。

- 抢先线程(/进程)模型中,每个线程(/进程)都被授予单独使用CPU,直到它明确放弃它为止。这是您在单用户操作系统中找到的模型,例如原始Windows或Macintosh(以及早于它们的一堆小型计算机系统)。正在运行的进程可以明确yield()其对处理器的控制,允许另一个线程/进程运行。当然,有很多警告,特别是关于中断处理,但我会在那里留下描述。

在抢先式,即分时共享模型中,操作系统可能强制线程/进程产生CPU(即“抢占”它)。这可能发生在任何地方,但在最简单的情况下,OS会在每个时钟周期调用,并决定哪个进程应该让CPU进入下一个时钟周期。再次简化,具有最高优先级的进程可以运行;如果有多个进程具有相同的优先级,则最近运行的算法通常会决定。

但是,无论如何,对于所有现代Java实现,操作系统决定何时(以及在何处)运行线程,而不是JVM。

答案 1 :(得分:1)

不是线程专家,但让线程无限期运行会导致饥饿。你仍然会给予低优先级的一些时间。我相信时间共享给所有线程基本相同的数量。 These notes可能会有所帮助。

来自上述说明:

  

非抢占式调度:当前进程释放CPU       终止或切换到等待状态。 (在MS Windows系列中使用)

     
      
  • 优点:   
        
    • 缩短周转时间
    •   
    • 不需要特殊的硬件(例如,计时器)
    •   
  •   
  • 缺点   
        
    • 有限的调度算法选择
    •   
  •   
     

抢先式调度:当前进程需要非自愿地释放   当一个更重要的进程插入就绪队列或一次时,CPU   已分配的CPU时间已过。 (用于Unix和类Unix系统)

     
      
  • 优点:   
        
    • 对调度算法的选择没有限制
    •   
  •   
  • 缺点:   
        
    • 额外开销(例如,更频繁的上下文切换,HW定时器,协调访问数据等)
    •   
  •   

答案 2 :(得分:0)

实际上,线程是一个抽象概念。它只是一个应该执行的原子过程。原子,我的意思是一个过程,如果你停止它(例如因为它太长而你想要执行另一个),你需要存储它的当前状态并在继续执行该过程之前恢复它。现在,这个过程取决于你想要的是什么。例如,在C语言中,如果我记得很好,那么这个语言就是为了构建操作系统而设计的,一个过程基本上就是一个程序。该程序可以要求系统运行其他程序,或者自行分叉以运行克隆(通过使用fork()函数)。无论是不同的程序还是克隆,它无论如何都是一个不同的过程,应该以原子方式执行。在C中,线程是一个程序。在Java中,线程是一个扩展Thread的类。在C中,通过执行main()函数启动线程/程序,在Java中,通过执行run()方法运行线程/类。这仅适用于线程概念。它只是程序的通用名称或执行的Thread实例。

现在,计算机需要并行执行许多东西。它导致同时管理多个线程。这是线程池:它是要执行的线程列表。而已。一个简单的清单。但是有了这个,你就拥有了调度程序:你有一个给定数量的"处理器",你需要决定在它们上执行哪些线程,但你不能执行比你拥有更多的线程"处理器& #34 ;.调度程序策略应设计为尽可能节省时间,这取决于线程的内容和依赖性。可以使用不同的策略,如平衡执行时间,循环,优先级等。

我把"处理器"在引号中,因为我的意思是在这里"计算单位"。它可以是计算机或CPU的物理处理器,现在通常具有2到8个内核(意味着它可以同时运行2-8个线程),并执行CPU指令(通常是RISC)。它可以是图形卡或GPU的处理器,它具有几十或几百个内核,但使用不同的指令集。 Iit也可以是来自Java虚拟机或JVM的处理器,它只能运行单个线程并使用自己的一组指令(字节码)。 JVM和前两个之间的主要区别在于CPU和GPU直接与硬件交互,没有中介,而JVM将自己的字节码转换为RISC指令并要求CPU执行它们。

CPU使用自己的调度程序来执行其线程(RISC指令集合,而不仅仅是一个)。我们称之为"系统线程"。但是当您使用Java编程时,您的执行环境不是系统,而是JVM,它为您提供系统的抽象(这是您可以在任何计算机上运行Java程序而无需关心下面的系统)。这意味着您不能直接与系统通信,因此Java为您提供了一种在自己的级别处理线程的方法,允许您创建线程(新的Thread())并将它们提供给调度程序(SwingUtilities,执行人等)。如何将Java线程转换为系统线程,以及如何使用Java调度程序替换系统调度程序,这是JVM的工作。

因此,当您谈论Java中的线程时,您不会在系统级别谈论线程。这是将与系统交互的JVM,以便您具有类似的行为。但是您的Java线程不是由CPU管理的,因此您可以独立于CPU的调度策略来请求特定的调度策略。

Java中的线程调度是如何完成的?可从:https://www.researchgate.net/post/How_is_Thread_scheduling_in_Java_done [2017年5月22日访问]。

答案 3 :(得分:0)

这个答案可以在另一个来源找到..我很困惑。但无论如何都要发帖。 我实际上并不了解Java规范或JVM的实际实现方式。但是,这是我的理由。有些人提到JVM只能在操作系统上运行一个线程,并在JVM内部进行自己的调度。对我来说,这没有意义,因为与使用几个真正的操作系统级线程的其他软件相比,您的Java软件会有更糟糕的性能(在简化视图中,每个操作系统线程都会获得相同的时间,以及几个Java线程必须共享单个OS线程的时间。)

因此,JVM更有可能为您在Java中创建的每个线程启动操作系统级线程。然后由操作系统来调度线程。在Java中指定线程优先级可以不同地映射到OS线程,具体取决于JVM的实现和操作系统的功能。例如,对于Linux,优先级与循环调度相结合。它主要取决于为线程安排的时间量。时间片不应该变为零长度,这样就可以防止线程完全饥饿。但是,有可能在Linux中使用实时线程(可能无法从Java访问),以使操作系统完全没有响应。

我想Java规范提到了抢占式线程调度,因为进行多线程只有两种主要方式:抢占式调度和协作式多线程。对于抢占式多线程,您需要硬件和操作系统的支持。另一方面,协作多线程意味着您必须在源代码中调用函数来主动在线程之间切换。如果您自己的源代码没有调用此函数,则在协作多线程中不能运行其他线程。

作为对其中一个答案的回答,您还询问了线程池。通常,线程池按以下方式使用:您有一个具有固定线程数的池。例如,这可能是每个核心一个线程。创建线程池后,所有线程都没有任何工作要做。现在,您可以将任务分配给池。然后,池将使用其线程最终为每个任务提供结果。这样做的好处是,您可以向池中输入比实际线程更多的任务。这是一种简单的方法,不会同时使用太多线程重载系统(通过每个任务同时使用一个线程)。要了解更多相关信息,您可以查找“期货”。

Java中的线程调度是如何完成的?可从:https://www.researchgate.net/post/How_is_Thread_scheduling_in_Java_done [2017年5月22日访问]。