zoukankan      html  css  js  c++  java
  • Java多线程--线程的调度

           java虚拟机会按照特定的机制为程序中的每个线程分配CPU的使用权,这种机制被称为线程的调度。  

      在计算机中,线程调度有两种模型,分别是分时调度模型和抢占式调度模型。

    分时调度模型:

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

    抢占式调度模型:

      让可运行迟中优先级高的线程优先占用CPU,而对于优先级相同的线程,随机选择一个线程使其占用CPU,当它失去了CPU的使用权后,再随机选择其它线程获取CPU的使用权。

      java虚拟机默认采用抢占式调度模型,但在某些特定的需求下需要改变这种模型,由线程自己来控制CPU的调度。

     

    线程的优先级:

      如果要对线程进行调度,最直接的方法就是设置线程的优先级。 

      在线程中有优先级的机制,线程的优先级用1~10之间的整数来表示,数字越大则表示优先级越高。除了数字,还可以使用Thread类中提供的三个静态常量表示线程的优先级,他们分别是:MAX_PRIORITY、MIN_PRIORITY、NORM_PRIORIY。

      优先级高的线程获得CPU执行的机会越大,而优先级低的线程获得CPU执行的机会越小。在默认情况下,每个线程都有自己的优先级,例如main线程具有普通优先级。线程优先级不是固定不变的,通过调用Thread类的setPriority(int newPriority)方法可以进行改变,setPriority()方法的数newPriority接收1~10之间的数或者Thread类的三个静态常量

     1 @SpringBootTest
     2 //定义MaxPriority,实现Runnable接口
     3 class MaxPriority implements Runnable{
     4     //实现接口中的run()方法
     5     @Override
     6     public void run() {
     7         for (int i = 0; i <5; i++) {
     8             System.out.println(Thread.currentThread().getName() + "正在输出!");
     9         }
    10     }
    11 }
    12 //定义MinPriority,实现Runnable接口
    13 class MinPriority implements Runnable{
    14     //实现接口中的run()方法
    15     @Override
    16     public void run() {
    17         for (int i = 0; i <5; i++) {
    18             System.out.println(Thread.currentThread().getName() + "正在输出!");
    19         }
    20     }
    21 }
    22 public class Example {
    23     public static void main(String[] args) {
    24         //创建两个线程
    25         Thread minPriority = new Thread(new MinPriority(),"优先级较低的线程");
    26         Thread maxPriority = new Thread(new MaxPriority(),"优先级较高的线程");
    27         //设置线程的优先级为1
    28         minPriority.setPriority(1);
    29         //设置线程的优先级为10
    30         maxPriority.setPriority(10);
    31         //开启两个线程
    32         minPriority.start();
    33         maxPriority.start();
    34     }
    35  }

    程序运行结果:

       优先级较高的maxPriority线程会先运行,运行完毕后优先级较低的minPriority线程才开始运行。

     

    线程休眠

      如果希望人为地控制线程,使正在运行的线程暂停,将CPU让给别的线程,这时可以使用静态方法sleep(long millis)方法,该方法可以让当前正在运行的线程暂停一段时间,进入休眠等待状态。当前线程调用sleep(long millis)方法后,在指定时间(参数 millis)内是不会执行的,这样其它的线程就可以得到执行的机会了。

      sleep(long millis)方法声明抛出InterruptedExcption异常,因此在调用该方法时应该捕获异常,或者声明抛出异常。

     1 @SpringBootTest
     2 //定义SleepThread,实现Runnable接口
     3 class SleepThread implements Runnable{
     4     //实现接口中的run()方法
     5     @Override
     6     public void run() {
     7         for (int i = 0; i <5; i++) {
     8             if (i == 3){
     9                 try {
    10                     Thread.sleep(2000);//当前线程休眠2秒
    11                 }catch (InterruptedException e){
    12                     e.printStackTrace();
    13                 }
    14             }
    15             System.out.println("线程一正在输出:" + i);
    16             try {
    17                 Thread.sleep(500); //当前线程休眠500毫秒
    18             }catch (Exception e){
    19                 e.printStackTrace();
    20             }
    21         }
    22     }
    23 }
    24 public class Example {
    25     public static void main(String[] args) throws Exception{
    26         //创建一个线程
    27         new Thread(new SleepThread()).start();
    28         for (int i = 0; i < 10; i++) {
    29             if (i ==5){
    30                 Thread.sleep(2000);//当前线程休眠2秒
    31             }
    32             System.out.println("主线程正在输出:" + i);
    33             Thread.sleep(500); //当前线程休眠500毫秒
    34         }
    35     }
    36  }

    运行结果:

      17行和33行的目的是是让一个线程在一次打印后休眠500ms,从而使另一个线程获得执行机会,这样就可以实现两个线程的交替实行。

      在线程一的for循环中,当i==3时,调用Thread的sleep(2000)方法,使线程休眠2s,主线程得到执行机会,接着输出了3和4,这说明线程一进入了休眠等待状态。

      在主线程的for循环中,当i ==5时,也调用了Thread的sleep(2000)方法,使线程休眠2s,当主线程2s休眠结束后,两个线程才会恢复交替执行。

      sleep()是静态方法,只能控制当前正在运行的线程休眠,而不能控制其他线程休眠。当线程休眠结束后,线程就会返回就绪状态,而不是立刻开始运行。

    线程让步

      线程让步可以通过yield()方法来实现,该方法和sleep()方法有点相似,都可以让当前正在运行的线程暂停,区别在于yield()方法不会阻塞线程,它只是将线程转换成就绪状态,让系统的调度器重新调度一次。yield()方法结束后,只有与当前线程优先级相同或者更高的线程才能获得执行机会。

     1 @SpringBootTest
     2 //定义YieldThread,继承Thread类
     3 class YieldThread extends Thread{
     4     //定义一个有参的构造方法
     5     public YieldThread(String name) {
     6         super(name);
     7     }
     8     public void run() {
     9         for (int i = 0; i <5; i++) {
    10             System.out.println(Thread.currentThread().getName() + "---" + i);
    11             if (i == 3) {
    12                 System.out.println("线程让步:");
    13                 Thread.yield();
    14             }
    15         }
    16     }
    17 }
    18 public class Example {
    19     public static void main(String[] args) throws Exception{
    20         //创建两个线程
    21        Thread t1 = new YieldThread("线程A");
    22        Thread t2 = new YieldThread("线程B");
    23          //开启两个线程
    24         t1.start();
    25         t2.start();
    26     }
    27  }

    运行结果:

       如图,当线程B输出3以后,会做出让步,线程A继续执行,同样,当线程A输出3后,也会做出让步,线程B继续执行。

    线程插队

      当在某个线程中调用其他线程的join()方法时,调用的线程将被阻塞,直到被join()方法加入的线程执行完成之后它才会继续运行。

     1 @SpringBootTest
     2 //定义EmergencyThread类,实现Runnable接口
     3 class EmergencyThread implements Runnable{
     4     //实现接口中的run()方法
     5     @Override
     6     public void run() {
     7         for (int i = 1; i <6; i++) {
     8             System.out.println(Thread.currentThread().getName() + "输入:" + i);
     9                 try {
    10                     Thread.sleep(500);//当前线程休眠500毫秒
    11                 }catch (InterruptedException e){
    12                     e.printStackTrace();
    13                 }
    14         }
    15     }
    16 }
    17 public class Example {
    18     public static void main(String[] args) throws Exception{
    19         //创建线程
    20          Thread t = new Thread (new EmergencyThread(),"线程一");
    21          t.start();
    22         for (int i = 1; i < 6; i++) {
    23             System.out.println(Thread.currentThread().getName() +"输入:"+ i);
    24             if (i ==2){
    25                 t.join(); //调用join()方法
    26             }
    27             Thread.sleep(500); //当前线程休眠500毫秒
    28         }
    29     }
    30  }
    31  

    运行结果:

       main线程中开启了一个线程t,两个线程的循环体中都调用了Thread的sleep(500)方法,以实现两个线程的交替执行。当main()线程中的循环变量为2时,调用t线程的join()方法,这时,t线程就会“插队”优先执行。从运行结果来看,当main线程输出2后,线程一就开始执行,直到线程一执行完毕,main线程才继续执行。

  • 相关阅读:
    【博弈】UVA10561 Treblecross
    2021牛客暑期多校训练营2 部分题解
    2021牛客暑期多校训练营1 部分题解
    变量
    第六次作业
    第五次作业
    第四次作业
    第三次作业
    第二次作业
    c#下载网页源码的两种方法
  • 原文地址:https://www.cnblogs.com/wx60079/p/13260078.html
Copyright © 2011-2022 走看看