每个虚拟机都有一个线程调度器,确实在任何时刻运行哪个线程。有两种线程调度器:
1、抢占式(preemptive)
2、协作式(cooperative)
      抢占式线程高度器确实线程何时已经公平地享用了CPU时间,然后暂停此线程上,将CPU控制权交给另外的线程。协作式线程调度器会在将CPU控制权交给其他线程前,等待运行中的线程自己斩停。与使用抢占式线程式调度的虚拟机相比,使用协作式线程调度器的虚拟机更容易使线程陷入“饥饿”,因为一个高优先级的非协作线程会独占整个CPU。
      所有JAVA虚拟机都保证了在不同优先级之间使用抢占式线程调度。即,当高优先级线程准备运行时,而低优先级线程正在运行,虚拟机会或早或晚(可能是早)暂停低优先级线程,让高优先级的线程运行。高优先级线程就抢占(preempt)了低优先级别线程。
      JAVA的线程的优先级,以1到10的整数指定。当多个线程可以运行时,VM一般会运行最高优先级的线程,但这并非严格的规则。在JAVA中,10是最高优先级,1是最低优先级。默认优先级是5,除非有意设置,否则创建的线程都默认是这个优先级。
      JAVA以三个命名常量来指定三个优先级(1、5、10):

 /**
     * The minimum priority that a thread can have.
     */
    public final static int MIN_PRIORITY = 1;

   /**
     * The default priority that is assigned to a thread.
     */
    public final static int NORM_PRIORITY = 5;

    /**
     * The maximum priority that a thread can have.
     */
    public final static int MAX_PRIORITY = 10;

      线程的优先级可以使用setPriority()方法来改变:

 

pubilc final void setPriority(int newPriority);

      使用getPriority()方法可以返回线程的当前优先级:

public final int getPriority();

      如果多个相同优先级的线程准备运行,这种情况有些棘手。抢占式线程调度偶尔会暂停其中一个线程,让下一个线程得到一些CPU时间。但是,协作式线程高度器不会这样。它等待正在运行的线程显式放弃控制并到达停止点(即停止)。如果运行中线程永远不会放弃控制权,也永远不会到达停止点,并且没有更高优先级线程抢占运行中线程,那么其它所有线程都会“饥饿”。这是件坏事情。重要的一点是,要确保所有线程自身定期地暂停,这样其他线程才可以有运行的机会。

 

注意:

      如果在使用抢占式线程调度的VM上开发,饥饿问题就很难发现。这是因为没有过在你的机器上出现问题,并不表示不会在客户机器上出现,如果他们的VM使用协作式线程调度的话,就很可能出现问题。目前大多数虚拟机都使用抢占式线程调度,但有些更早的虚拟机是协作调度的。

 

      为了有利其他线程,一个线程有10种方式可以暂停或指示准备暂停。如下:

1、可以在I/O时阻塞
2、可以在同步对象时阻塞
3、可以放弃
4、可以休眠
5、可以连接另一个线程
6、可以等待一个对象
7、可以结束
8、可以被更高优先级线程抢占
9、可以被挂起
10、可以停止
      你应当检测你编写的的每个run()方法,确保这这些条件之一以合理的频率出现。最后两种可能性已经废弃不用,因为它们可能会让对象处于不一致的状态。

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐