`

java 线程调度策略

 
阅读更多

原博客:http://www.blogjava.net/santicom/archive/2011/09/01/357765.html

 

线程的状态与调度

  1,线程的生命周期

        线程从创建、运行到结束总是处于下面五个状态之一:新建状态、就绪状态、运行状态、阻塞状态及死亡状态。



    1.新建状态(New): 
        当用new操作符创建一个线程时, 例如new Thread(r),线程还没有开始运行,此时线程处在新建状态。 当一个线程处于新生状态时,程序还没有开始运行线程中的代码

     2.就绪状态(Runnable)

        一个新创建的线程并不自动开始运行,要执行线程,必须调用线程的start()方法。当线程对象调用start()方法即启动了线程,start()方法创建线程运行的系统资源,并调度线程运行run()方法。当start()方法返回后,线程就处于就绪状态。

        处于就绪状态的线程并不一定立即运行run()方法,线程还必须同其他线程竞争CPU时间,只有获得CPU时间才可以运行线程。因为在单CPU的计算机系统中,不可能同时运行多个线程,一个时刻仅有一个线程处于运行状态。因此此时可能有多个线程处于就绪状态。对多个处于就绪状态的线程是由Java运行时系统的线程调度程序(thread scheduler)来调度的。

    3.运行状态(Running)

        当线程获得CPU时间后,它才进入运行状态,真正开始执行run()方法.

    4. 阻塞状态(Blocked)

        线程运行过程中,可能由于各种原因进入阻塞状态:
        1>线程通过调用sleep方法进入睡眠状态;
        2>线程调用一个在I/O上被阻塞的操作,即该操作在输入输出操作完成之前不会返回到它的调用者;
        3>线程试图得到一个锁,而该锁正被其他线程持有;
        4>线程在等待某个触发条件;
        ......           

        所谓阻塞状态是正在运行的线程没有运行结束,暂时让出CPU,这时其他处于就绪状态的线程就可以获得CPU时间,进入运行状态。

    5. 死亡状态(Dead)

        有两个原因会导致线程死亡:
        1) run方法正常退出而自然死亡,
        2) 一个未捕获的异常终止了run方法而使线程猝死。
        为了确定线程在当前是否存活着(就是要么是可运行的,要么是被阻塞了),需要使用isAlive方法。如果是可运行或被阻塞,这个方法返回true; 如果线程仍旧是new状态且不是可运行的, 或者线程死亡了,则返回false.




2,  线程的优先级和调度

Java的每个线程都有一个优先级,当有多个线程处于就绪状态时,线程调度程序根据线程的优先级调度线程运行。

可以用下面方法设置和返回线程的优先级。

    · public final void setPriority(int newPriority) 设置线程的优先级。

    · public final int getPriority() 返回线程的优先级。

newPriority为线程的优先级,其取值为110之间的整数,也可以使用Thread类定义的常量来设置线程的优先级,这些常量分别为:Thread.MIN_PRIORITYThread.NORM_PRIORITYThread.MAX_PRIORITY,它们分别对应于线程优先级的1510,数值越大优先级越高。当创建Java线程时,如果没有指定它的优先级,则它从创建该线程那里继承优先级。

一般来说,只有在当前线程停止或由于某种原因被阻塞,较低优先级的线程才有机会运行。

前面说过多个线程可并发运行,然而实际上并不总是这样。由于很多计算机都是单CPU的,所以一个时刻只能有一个线程运行,多个线程的并发运行只是幻觉。在单CPU机器上多个线程的执行是按照某种顺序执行的,这称为线程的调度(scheduling)

大多数计算机仅有一个CPU,所以线程必须与其他线程共享CPU。多个线程在单个CPU是按照某种顺序执行的。实际的调度策略随系统的不同而不同,通常线程调度可以采用两种策略调度处于就绪状态的线程。

(1) 抢占式调度策略

     Java运行时系统的线程调度算法是抢占式的 (preemptive)Java运行时系统支持一种简单的固定优先级的调度算法。如果一个优先级比其他任何处于可运行状态的线程都高的线程进入就绪状态,那么运行时系统就会选择该线程运行。新的优先级较高的线程抢占(preempt)了其他线程。但是Java运行时系统并不抢占同优先级的线程。换句话说,Java运行时系统不是分时的(time-slice)。然而,基于Java Thread类的实现系统可能是支持分时的,因此编写代码时不要依赖分时。当系统中的处于就绪状态的线程都具有相同优先级时,线程调度程序采用一种简单的、非抢占式的轮转的调度顺序。

(2) 时间片轮转调度策略

    有些系统的线程调度采用时间片轮转(round-robin)调度策略。这种调度策略是从所有处于就绪状态的线程中选择优先级最高的线程分配一定的CPU时间运行。该时间过后再选择其他线程运行。只有当线程运行结束、放弃(yield)CPU或由于某种原因进入阻塞状态,低优先级的线程才有机会执行。如果有两个优先级相同的线程都在等待CPU,则调度程序以轮转的方式选择运行的线程。

 3.  线程状态的改变

一个线程在其生命周期中可以从一种状态改变到另一种状态,线程状态的变迁如图所示:

    
    
1>  控制线程的启动和结束

当一个新建的线程调用它的start()方法后即进入就绪状态,处于就绪状态的线程被线程调度程序选中就可以获得CPU时间,进入运行状态,该线程就开始运行run()方法。

控制线程的结束稍微复杂一点。如果线程的run()方法是一个确定次数的循环,则循环结束后,线程运行就结束了,线程对象即进入死亡状态。如果run()方法是一个不确定循环,早期的方法是调用线程对象的stop()方法,然而由于该方法可能导致线程死锁,因此从1.1版开始,不推荐使用该方法结束线程。一般是通过设置一个标志变量,在程序中改变标志变量的值实现结束线程。请看下面的例子:

程序 ThreadStop.java

import java.util.*;

class Timer implements Runnable{

    boolean flag=true;
    public void run(){
      while(flag){
        System.out.print("\r\t"+new Date()+"");
        try{
              Thread.sleep(1000);
        }catch(InterruptedException e){} 
      }
      System.out.println("\n"+Thread.currentThread().getName()+" Stop");
    }

    public void stopRun(){
           flag = false;
    }
}

public class ThreadStop{
    public static void main(String args[]){
       Timer timer = new Timer();
       Thread thread = new Thread(timer);       
       thread.setName("Timer");
       thread.start();

       for(int i=0;i<100;i++){
         System.out.print("\r"+i);
        try{
              Thread.sleep(100);
        }catch(InterruptedException e){} 
       }     
       timer.stopRun();
    }
}

该程序在Timer类中定义了一个布尔变量flag,同时定义了一个stopRun()方法,在其中将该变量设置为false。在主程序中通过调用该方法,从而改变该变量的值,使得run()方法的while循环条件不满足,从而实现结束线程的运行。

说明  在Thread类中除了stop()方法被标注为不推荐(deprecated) 使用外,suspend()方法和resume()方法也被标明不推荐使用,这两个方法原来用作线程的挂起和恢复.

2>  线程阻塞条件

处于运行状态的线程除了可以进入死亡状态外,还可能进入就绪状态和阻塞状态。下面分别讨论这两种情况:

(1) 运行状态到就绪状态

处于运行状态的线程如果调用了yield()方法,那么它将放弃CPU时间,使当前正在运行的线程进入就绪状态。这时有几种可能的情况:如果没有其他的线程处于就绪状态等待运行,该线程会立即继续运行;如果有等待的线程,此时线程回到就绪状态状态与其他线程竞争CPU时间,当有比该线程优先级高的线程时,高优先级的线程进入运行状态,当没有比该线程优先级高的线程时,但有同优先级的线程,则由线程调度程序来决定哪个线程进入运行状态,因此线程调用yield()方法只能将CPU时间让给具有同优先级的或高优先级的线程而不能让给低优先级的线程。

一般来说,在调用线程的yield()方法可以使耗时的线程暂停执行一段时间,使其他线程有执行的机会。

(2) 运行状态到阻塞状态

有多种原因可使当前运行的线程进入阻塞状态,进入阻塞状态的线程当相应的事件结束或条件满足时进入就绪状态。使线程进入阻塞状态可能有多种原因:

① 线程调用了sleep()方法,线程进入睡眠状态,此时该线程停止执行一段时间。当时间到时该线程回到就绪状态,与其他线程竞争CPU时间。

Thread类中定义了一个interrupt()方法。一个处于睡眠中的线程若调用了interrupt()方法,该线程立即结束睡眠进入就绪状态。

② 如果一个线程的运行需要进行I/O操作,比如从键盘接收数据,这时程序可能需要等待用户的输入,这时如果该线程一直占用CPU,其他线程就得不到运行。这种情况称为I/O阻塞。这时该线程就会离开运行状态而进入阻塞状态。Java语言的所有I/O方法都具有这种行为。

③ 有时要求当前线程的执行在另一个线程执行结束后再继续执行,这时可以调用join()方法实现,join()方法有下面三种格式:

·         public void join() throws InterruptedException 使当前线程暂停执行,等待调用该方法的线程结束后再执行当前线程。

·         public void join(long millis) throws InterruptedException 最多等待millis毫秒后,当前线程继续执行。

·         public void join(long millis, int nanos) throws InterruptedException 可以指定多少毫秒、多少纳秒后继续执行当前线程。

上述方法使当前线程暂停执行,进入阻塞状态,当调用线程结束或指定的时间过后,当前线程线程进入就绪状态,例如执行下面代码:

t.join();

将使当前线程进入阻塞状态,当线程t执行结束后,当前线程才能继续执行。

④ 线程调用了wait()方法,等待某个条件变量,此时该线程进入阻塞状态。直到被通知(调用了notify()notifyAll()方法)结束等待后,线程回到就绪状态。

⑤ 另外如果线程不能获得对象锁,也进入就绪状态。

分享到:
评论

相关推荐

    线程 JAVA java线程 java线程第3版 java线程第2版第3版合集

    电子书相关:包含4个有关JAVA线程的电子书(几乎涵盖全部有关线程的书籍) OReilly.Java.Threads.3rd.Edition....第七章 Java线程调度例子 第八章 和同步相关的高级主题 第九章 多处理器机器上的并行化 第十章 线程组

    java并发编程面试题

    线程的调度策略 sleep() 和 wait() 有什么区别? 什么是线程同步和线程互斥,有哪几种实现方式? Java 线程数过多会造成什么异常? 并发编程-Java内存模型 ## as-if-srial规则和happens-before规则的区别 ...

    (超赞)JAVA精华之--深入JAVA API

    1.6 Java线程 1.7 Java 5.0多线程编程 1.8 Java Socket编程 1.9 Java的内存泄漏 1.10 抽象类与接口的区别 1.11 Java变量类型间的相互转换 2 JAVA与WEB 2.1 JMX规范 2.1.1 JMX概述 2.1.2 设备层(Instrumentation ...

    Java并发编程及高并发解决方案

    第9章线程调度-线程池 第10章多线程并发拓展 第11章高并发之扩容思路 第12章高并发之缓存思路 第13章高并发之消息队列思路 第14章高并发之应用拆分思路 第15章高并发之应用限流思路 第16章高并发之服务降级与服务...

    Java多线程编程之限制优先级

    限制线程优先级和调度 Java 线程模型涉及可以动态更改的线程优先级。本质上,线程的优先级是从 1 到 10 之间的一个数字,数字越大表明任务越紧急。JVM 标准首先调用优先级较高的线程,然后才调用优先级较低的线程。...

    利用Java实现的银行业务调度系统

    利用Java实现简单的银行业务窗口排队调度,包括多个窗口,利用线程池解决多线程问题。

    JAVA SE学习精华集锦

    1.6 Java线程 60 1.7 Java 5.0多线程编程 65 1.8 Java Socket编程 80 1.9 Java的内存泄漏 85 1.10 抽象类与接口的区别 86 1.11 Java变量类型间的相互转换 87 2 JAVA与WEB 87 2.1 JMX规范 87 2.1.1 JMX概述 87 2.1.2 ...

    java面试题库2021.pdf

    ①线程 ②锁 ③JDK ④反射 ⑤JVM ⑥GC ⑦ IO 和 NIO, AIO 二、 JavaEE 部分 1、 Spring ①IoC 与 Bean 配置、 管理 ②AOP 与事务、 权限控制 ③S2SH 整合开发 ④Spring, JPA 整合 2、 Hibernate ①ORM 与持久化...

    深入理解_Java_虚拟机 JVM_高级特性与最佳实践

    / 327 12.3.5 原子性、可见性与有序性 / 328 12.3.6 先行发生原则 / 330 12.4 Java与线程 / 333 12.4.1 线程的实现 / 333 12.4.2 Java线程调度 / 337 12.4.3 状态转换 / 339 12.5 本章小结 / 341 第13章 ...

    Java并发编程(学习笔记).xmind

    委托是创建线程安全类的最有效策略,只需要让现有的线程安全类管理所有的状态 在现有线程安全类中添加功能 将同步策略文档化 基础构建模块 同步容器类 分类 Vector Hashtable 实现...

    Java虚拟机

    12.4.2 Java线程调度 12.4.3 状态转换 12.5 本章小结 第13章 线程安全与锁优化 13.1 概述 13.2 线程安全 13.2.1 Java语言中的线程安全 13.2.2 线程安全的实现方法 13.3 锁优化 13.3.1 自旋锁与自适应自旋 ...

    java 面试题 总结

    JAVA相关基础知识 1、面向对象的特征有哪些方面 1.抽象: 抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面。抽象并不打算了解全部问题,而只是选择其中的一部分,暂时不用...

    Java™ Servlet 规范.

    其他的 Java 平台规范 .......................................................................................................................................3 其他重要参考资料 ............................

    java核心知识点整理.pdf

    25 JAVA8 与元数据.................................................................................................................................25 2.4. 垃圾回收与算法 .................................

    第7章-JUC多线程v1.1.pdf

    JAVA线程基本学习, JAVA多线程的特性= 线程池: 本质上是一个对象池, 用来管理线程资源. 在任务执行前, 需要从线程池中拿出线程来执行. 在任务执行完成之后, 需要把线程放回线程池. 线程池好处: 降低资源的消耗...

    JobScheduler:作业调度程序可在N个线程上调度M个作业

    首先缩短作业(SJF),这是一种调度策略,它选择执行时间最短的等待进程来执行。 如果是平局,请按照以下顺序选择工作: 优先级(优先级较高的作业先安排) 先来先服务 工作以先到先得的原则执行。 将输入作为需要...

    超级有影响力霸气的Java面试题大全文档

    超级有影响力的Java面试题大全文档 1.抽象: 抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面。抽象并不打算了解全部问题,而只是选择其中的一部分,暂时不用部分细节。...

    JAVA核心知识点整理(有效)

    25 JAVA8 与元数据.................................................................................................................................25 2.4. 垃圾回收与算法 .................................

    论文研究-实时CORBA平台依赖层的研究和实现.pdf

    目前实时CORBA在电信、电子商务、证券、复杂工业控制等领域发挥着越来越重要的作用。针对这些应用的特点,首先论述了分布式...具有固定优先级的调度策略,在提供灵活的线程管理的同时,能够有效地防止优先级反转。

    搜索引擎中网络蜘蛛的设计与实现

    :文章从搜索引擎的应用出发,探讨了网络蜘蛛在搜索...在对网络蜘蛛系统结构和工作原理所作分析的基础上,研究了线程调度、页面爬取、解析等策略和算法,并使用Java 实现了一个网络蜘蛛的程序,对其运行结果做了分析。

Global site tag (gtag.js) - Google Analytics