关闭

Java多线程的调度策略

标签: 多线程调度策略抢占式协同式时间片轮转
8625人阅读 评论(10) 收藏 举报
分类:

Java多线程环境中,为保证所有线程的执行能按照一定的规则执行,JVM实现了一个线程调度器,它定义了线程调度的策略,对于CPU运算的分配都进行了规定,按照这些特定的机制为多个线程分配CPU的使用权。这小节关注线程如何进行调度,了解了java线程调度模式有助于后面并发框架的深入探讨。

一般线程调度模式分为两种——抢占式调度和协同式调度。抢占式调度指的是每条线程执行的时间、线程的切换都由系统控制,系统控制指的是在系统某种运行机制下,可能每条线程都分同样的执行时间片,也可能是某些线程执行的时间片较长,甚至某些线程得不到执行的时间片。在这种机制下,一个线程的堵塞不会导致整个进程堵塞。协同式调度指某一线程执行完后主动通知系统切换到另一线程上执行,这种模式就像接力赛一样,一个人跑完自己的路程就把接力棒交接给下一个人,下个人继续往下跑。线程的执行时间由线程本身控制,线程切换可以预知,不存在多线程同步问题,但它有一个致命弱点:如果一个线程编写有问题,运行到一半就一直堵塞,那么可能导致整个系统崩溃。


2-5-6-1

为更加形象说明两种模式的不同,看图2-5-6-1,左边为抢占式线程调度,假如三条线程需要运行,处理器运行的路径是在线程一运行一个时间片后强制切换到线程二运行一个时间片,然后切到线程三,再回到线程一,如此循环直至三条线程都执行完。而协同式线程调度则不这样走,它会先将线程一执行完,线程一再通知线程二执行,线程二再通知线程三,直到线程三执行完。

在了解了两种线程调度模式后,现在考虑Java使用的是哪种线程调度模式。此问题的讨论涉及到JVM的实现,JVM规范中规定每个线程都有优先级,且优先级越高越优先执行,但优先级高并不代表能独自占用执行时间片,可能是优先级高得到越多的执行时间片,反之,优先级低的分到的执行时间少但不会分配不到执行时间。JVM的规范没有严格地给调度策略定义,我想正是因为面对众多不同调度策略,JVM要封装所有细节提供一个统一的策略不太现实,于是给了一个不严谨但足够统一的定义。回到问题上,Java使用的线程调度是抢占式调度,在JVM中体现为让可运行池中优先级高的线程拥有CPU使用权,如果可运行池中线程优先级一样则随机选择线程,但要注意的是实际上一个绝对时间点只有一个线程在运行(这里是相对于一个CPU来说,如果你的机器是多核的还是可能多个线程同时运行的),直到此线程进入非可运行状态或另一个具有更高优先级的线程进入可运行线程池,才会使之让出CPU的使用权,更高优先级的线程抢占了优先级低的线程的CPU

Java中线程会按优先级分配CPU时间片运行,那么线程什么时候放弃CPU的使用权?可以归类成三种情况:

  1. 当前运行线程主动放弃CPUJVM暂时放弃CPU操作(基于时间片轮转调度的JVM操作系统不会让线程永久放弃CPU,或者说放弃本次时间片的执行权),例如调用yield()方法。

  2. 当前运行线程因为某些原因进入阻塞状态,例如阻塞在I/O上。

  3. 当前运行线程结束,即运行完run()方法里面的任务。

三种情况中第三种很好理解,任务执行完了自然放弃CPU,前两种情况用两个例子说明,先看使用yield放弃CPU什么情况:

public class YeildThread {

publicstatic void main(String[] args) {

    MyThreadmt = new MyThread();

    mt.start();

    while(true) {

         System.out.println("主线程");

    }

}

}

 

class MyThread extends Thread {

publicvoid run() {

    while(true) {

         System.out.println("被放弃线程");

         Thread.currentThread().yield();

    }

}

}

截取某段输出如下,输出“主线程”比“被放弃线程”运行的机会多,因为mt线程每次循环都把时间片让给主线程,正是因为yield操作并不会永远放弃CPU,仅仅只是放弃了此次时间片,把剩下的时间让给别的线程,

主线程

主线程

主线程

主线程

主线程

主线程

被放弃线程

主线程

主线程

主线程

主线程

主线程

主线程

主线程

 

第二个例子为节省代码量将使用伪代码表示,例子简单但已能说明问题,运行程序将有两条线程工作,ioThread每次遇到I/O阻塞就放弃当前的时间片,而主线程则按JVM分配的时间片正常运行。

public class IOBlockThread {

publicstatic void main(String[] args) {

     IOThread ioThread = new IOThread();

     ioThread.start();

    主线程任务执行

}

}

 

class IOThread extends Thread {

publicvoid run() {

    while(true) {

         I/O阻塞

    }

}

}

 

Java的线程的调度机制都由JVM实现,假如有若干条线程,你想让某些线程拥有更长的执行时间,或某些线程分配少点执行时间,这时就涉及“线程优先级”,Java把线程优先级分成10个级别,线程被创建时如果没有明确声明则使用默认优先级,JVM将根据每个线程的优先级分配执行时间的概率。有三个常量Thread.MIN_PRIORITYThread.NORM_PRIORITYThread.MAX_PRIORITY分别表示最小优先级值(1)、默认优先级值(5)、最大优先级值(10)。

由于JVM的实现以宿主操作系统为基础,所以Java优先级值与各种不同操作系统的原生线程优先级必然存在某种映射关系,这样才足以封装所有操作系统的优先级提供统一优先级语义。例如1-10优先级值在linux可能要与0-99优先级值进行映射,而windows系统则有7个优先级要映射。

线程的调度策略决定上层多线程运行机制,JVM的线程调度器实现了抢占式调度,每条线程执行的时间由它分配管理,它将按照线程优先级的建议对线程执行的时间进行分配,优先级越高,可能得到CPU的时间则越长。

 


点击订购作者书籍《Tomcat内核设计剖析》


=====================================

公众号的菜单已分为“分布式”、“机器学习”、“深度学习”、“NLP”、“Java深度”、“Java并发核心”、“JDK源码”、“Tomcat内核”等,可能有一款适合你的胃口。


鄙人的新书《Tomcat内核设计剖析》已经在京东销售了,有需要的朋友可以购买。感谢各位朋友。


[为什么写《Tomcat内核设计剖析》](http://blog.csdn.net/wangyangzhizhou/article/details/74080321)

==================================================




1
1
查看评论
发表评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场

一篇博文彻底了解线程的调度策略

线程的调度策略 在java的线程开发中,线程的调度策略是一个很重要的知识点,起承上启下的作用,所以我们下面去一起看看系统是怎么安排线程之间的运行规则的。 线程调度的目的 首先我们要知道,...
  • farley119
  • farley119
  • 2016-12-04 22:19
  • 1405

Java 多线程编程之八:多线程的调度

本博客是“Java 多线程编程”系列的后续篇。“Java 多线程编程”系列其他博客请参阅本博客结尾部分。         有多个线程,如何控制它们执行的先后次序?         方法一:设置线程优先...
  • defonds
  • defonds
  • 2013-03-12 18:08
  • 12185

Java多线程的调度_动力节点Java学院整理

  • 2017-11-07 16:34
  • 81KB
  • 下载

Java线程池架构2-多线程调度器(ScheduledThreadPoolExecutor)

在前面介绍了java的多线程的基本原理信息:《Java线程池架构原理和源码解析(ThreadPoolExecutor)》,本文对这个java本身的线程池的调度器做一个简单扩展,如果还没读过上一篇文章,...
  • xieyuooo
  • xieyuooo
  • 2013-04-29 03:58
  • 9665

(新手)java多线程基础知识——调度与同步

以前写过一篇关于多线程的总结: http://kyfxbl.iteye.com/blog/1370377 很久没用到,忘记了。最近又遇到了一些多线程的问题,重新查了些资料,再提炼一下。本文不涉及ja...
  • kyfxbl
  • kyfxbl
  • 2013-09-24 11:22
  • 633

2011-09-07 java多线程临界资源同步和调度问题,遇到困难加锁和解锁问题

继续昨天内容-java多线程的同步问题。大家都知道要实现同步问题要使用synchronized标记,synchronized标记标记的方法或对象就被带调用此方法或使用此对象的线程加锁说定了,只有当这个...
  • Imust_can
  • Imust_can
  • 2011-09-07 22:36
  • 1373

Java多线程调度方法

多线程
  • fumier
  • fumier
  • 2015-03-19 20:41
  • 792

java多线程-Thread线程调度CyclicBarrier循环屏障

背景 上次说完了CountDownLatch,是一个计数器,这次说说CyclicBarrier,循环屏障,我先直观的说明,这也能看做为一个计数器,属于加法计数器,而CountDownLatch,是减法...
  • u013728415
  • u013728415
  • 2017-04-25 10:27
  • 139

Java多线程3—线程的调度和runnable接口优点

Java运行时系统实现了一个用于调度线程执行的线程调度器,用于确定某一时刻由哪一个线程在CPU上运行。在java技术中,线程通常是抢占式的而不需要时间片分配进程(分配给每个线程相等的CPU时间的进程)...
  • shaojinxuan2010
  • shaojinxuan2010
  • 2011-11-02 09:33
  • 2904

Java多线程:线程调度Join

public final void join() throws InterruptedException 等待该线程终止。 public final void join(long millis) ...
  • huang_xw
  • huang_xw
  • 2012-03-11 16:39
  • 2007
    作者
    https://github.com/sea-boat

    公众号:(内容包括分布式、机器学习、深度学习、NLP、Java深度、Java并发核心、JDK源码、Tomcat内核等等)



    微信:

    打赏作者

    如果您觉得作者写的文章有帮助到您,您可以打赏作者一瓶汽水(*^__^*)

    个人资料
    • 访问:1008958次
    • 积分:13508
    • 等级:
    • 排名:第1118名
    • 原创:319篇
    • 转载:5篇
    • 译文:1篇
    • 评论:340条
    博客专栏
    最新评论