1.Java线程的运行机制

  在Java 虚拟机进程中,执行程序代码的任务是由线程来完成的。每个线程都有一个独立的程序计数器和方法调用栈(methodinvocationstack)

  1.程序计数器: 也称为PC 寄存器,当线程执行一个方法时,程序计数器指向方法区中下一条要执行的字节码指令。

  2.方法调用栈:简称方法栈,用来跟踪线程运行中一系列的方法调用过程,栈中的元素称为栈帧。

  每当线程调用一个方法的时候,就会向方法栈压入一个新帧。帧用来存储方法的参数、局部变量和运算过程中的临时数据。

  栈帧由以下3 部分组成。

  3.局部变量区: 存放局部变量和方法参数。

  4.操作数栈: 是线程的工作区,用来存放运算过程中生成的临时数据。

  5.栈数据区:为线程执行指令提供相关的信息,包括如何定位到位于堆区和方法区的特定数据,以及如何正常退出方法或者异常中断方法。

示例:

当主线程执行main0方法时,会创建两个Machine 对象,然后启动两个Machine线程,接着主线程开始执行第一个Machine 对象的run0方法。在Java虚拟机中有三个

线程并发执行Machine 对象的run0方法。在三个线程各自的方法栈中都有代表run0方法的栈帧,在这个帧中存放了局部变量a,可见每个线程都拥有自己的局部变量a,

它们都分别从0增加到50。

 

 

 2.线程的状态转换

   1.线程的状态转换图

 

2.线程的几种状态

  1.新建状态(New)

    用New语句创建的线程对象处于新建状态此时他和其他Java对象一样仅仅在堆区中分配的内存。

  2.就绪状态(Runnable)当一个线程对象创建后,其他线程调用它的tart0方法,该线程就进入就绪状态,

    Java 虚拟机会为它创建方法调用栈和程序计数器。处于这个状态的线程位于可运行池中,等持获得CPU的使用权。

  3.运行状态(Running)

    处于这个状态的线程古用CPU,执行程序代码。在并发运行环境中,如果计算机只有一个CPU,那么任何时刻只会有一个线程处于这个状态。如果计算机有多个CPU,

    那么同一时刻可以让几个线程占用不同的CPU,使它们都处于运行状态,只有处于就绪状态的线程才有机会转到运行状态。

  4.阻塞状态(Blocked)

    阳塞状态是指线程因为某些原因放弃CPU,暂时停止运行,当线程处于阳塞状态时,Java虚拟机不会给线程分配CPU,直到线程重新进入就绪状态,它才有机会转到运行状态。

    阳塞状态可分为以下3种。

    ★位于对象等特池中的阻塞状态(Blockedinobjet'saitpo 当线程处于运行状态时,如果执行了某个对象的wait方法,Java虚拟机就会把线程放到这

    个对象的等待池中,参见本章第139节(线程通信)。

    ★位于对象锁池中的阻塞状态(Blockdiojgctesloco 当线程处于运行状态,试图获得某个对象的同步锁时,如果该对象的同步锁已经被其他线程

    占用,Java虚拟机就会把这个线程放到这个对象的锁池中,参见本幸第138节(线程的同步)。

    ★其他阳塞状态(OtherwiseBlocked)当前线程执行了seep0方法,或者调用了其他线程的join0方法,或者发出了IO请求时,就会进入这个状态。

   死亡状态(Dead)

    当线程退出run(O方法时,就进入死亡状态,该线程结束生命周期。线程有可能是正常执行完run(方法而退出,也有可能是遇到异常而退出。不管线程正常结束还是异

    常结束,都不会对其他线程造成影响。例如在例程13-9 中,Machine 线程在运行时为抛出RuntimeException 异常而结束,此时主线程继续正常运行直至结束。 

   

    当一个线程执行Systmoutprinin或者Systeminread0方法时,就会发出个IO请求,该线程放弃CPU,进入阴寨状态,直到1O处理完毕,该线程才会恢复运行。

    例如在例程13-8的Machine类中,主线程在启动个Mactine线程后,就等待用户的标准输入。主线程进入阻塞状态,Machine 线程占用CPU,继续运行。直到用户输入

    数据,主线程才会恢复运行。

 3.线程调度

      计算机通常只有一个CPU,在任意时刻只能执行一条机器指令,每个线程只有获得CPU的使用权才能执行指令。所谓多线程的并发运行,其实是指从宏观上看,各个

  线程轮流获得CPU的使用权,分别执行各自的任务。在可运行池中,会有多个处于就绪状态的线程在等待CPU,Java 虚拟机的一项任务就是负责线程的调度。线程的调度

  是指按照特定的机制为多个线程分配CPU 的使用权。有两种调度模型: 分时调度模型和抢占式调度模型。

      分时调度模型是指让所有线程轮流获得CPU 的使用权,并且平均分配每个线程占用CPU 的时间片。

      Java 虚拟机采用抢占式调度模型,是指优先让可运行池中优先级高的线程占用CPU,如果可运行池中线程的优先级相,那么就随机选择一个线程,使其占用CPU。

  处于运行状态的线程会一直运行,直至它不得不放弃CPU。一个线程会因为以下原因而放弃CPU。

    ★Java虚拟机让当前线程暂时放弃CPU,转到就绪状态,使其他线程获得运行机会。

    ★当前线程因为某些原因而进入阻塞状态。

    ★线程运行结束。

  值得注意的是,线程的调度不是跨平台的,它不仅取决于Java虚拟机,还依赖于操作系统。在某些操作系统中,只要运行中的线程没有遇到阻塞,就不会放弃CPU;

  在某些操作系统中,即使运行中的线程没有遇到阻塞,也会在运行一段时间后放弃CPU,给其他线程运行的机会。

 

  Java 线程的调度不是分时的,同时启动多个线程后,不能保证各个线程轮流获得均等的CPU 时间片。例程13-10 (Machine.java) 可以证明这一一点。

 

  线程睡眠:Thread.sleep( )方法

    当一个线程在运行中执行了sleep(方法时,它就会放弃CPU,转到阻塞状态。下面对13.4 节开头的例程13-10的Machine 类的run(方法做如下修改,使线程执行完一

    次循环时,就睡眠100毫秒。

 

  线程让步: Thead.yield0方法

    当线程在运行中执行了Thread类的yield0静态方法,如果此时具有相同优先级的其他线程处于就绪状态,那么yield0方法将把当前运行的线程放到可运行池中并使另

    个线程运行。如果没有相同优先级的可运行进程,则yield(方法什么都不做。下面对13.4 节开头的例程13-10的run0方法做如下修改,使线程在执行完一次循

    环后,就执行yield()方法。

 

  等待其他线程结束: join()

    当前运行的线程可以调用另一个线程的join0方法,当前运行的线程将转到阻塞状态,直至另一个线程运行结束,它才会恢复运行。

 

posted on 2018-03-11 17:06  ↑↑↓↓←→←→  阅读(99)  评论(0编辑  收藏  举报