mac_girl

多线程的创建、匿名内部类方式创建线程、定义、调度步骤

多线程

并发、并行

  • 并行 :
    具有在同一时刻干两件或两件以上事情的能力,几件件事同一时刻进行。(同时执行)
    情景 : 正在吃饭,有人打电话过来

               一边吃饭,一边打电话
    

    当前事未完成事,可以同时干这件事和另一件事

  • 并发
    具有在某个时间段做两件或两件以上事情的能力,几件事情在同一个时间段进行。(交错执行)
    情景: 正在吃饭,有人打电话过来
    停下吃饭的动作,接听电话,接听完电话,继续吃饭。
    当前事未完成时,可以暂时停止这件事,去干另一件事

  • 非并行,非并发

        情景:    正在吃饭,有人打电话过来
    
                      继续吃饭,吃完饭再接听电话
    
         必须完成当前这件事才能去干另一件事
    

进程、线程

  • 进程
    被加载入内存(RAM),正在运行的程序,且具有独立的功能
  • 线程
    进程的一个执行单元,负责进程中程序的执行,一个进程有多个线程
    线程相当于通向cup的一条道路
  • 程序、进程、线程 三者的关系
    程序 > 进程 > 线程
    一个程序至少有一个进程,一个进程至少有一个线程,含有多个线程的程序称为多线程程序。

其他

创建多线程

两种方法:

  • 继承Thread类

      1.继承Thread类
    
       2.复写run()方法
    
       3.创建线程对象,调用start()方法,开启线程
    

    /**
    *创建一个多线程实现Thread类
    */
    public class SubThread01 extends Thread {
    @Override
    public void run() {
    for (int j = 0; j < 20; j++) {
    System.out.println("subThread====" + j);
    }
    }
    }

    public class SubThreadDemo01 {
    public static void main(String[] args) {
    //创建线程
    SubThread01 subth = new SubThread01();
    //开启线程
    subth.start();
    for (int i = 0; i < 20; i++) {
    System.out.println("main====" + i);
    }
    }
    }

  • 实现Runable接口

    1. 实现 Runable接口

    2. 复写run方法

    3. 创建线程对象

    4. 创建Thread类,放入线程对象
      Thread th = new Thread(线程对象)

    5. th.start()
      /**
      *使用Runable创建一个线程类
      */
      public class RunThread01 implements Runnable {
      @Override
      public void run() {
      for (int i = 0; i <20; i++) {
      System.out.println("runthread===" + i);
      }
      }
      }

      public class RunThreadDemo01 {
          public static void main(String[] args) {
              //创建线程对象
              RunThread01 rth = new RunThread01();
              //开启线程
              Thread th = new Thread(rth);
              th.start();
              for (int i = 0; i <20; i++) {
                  System.out.println("run_main" + i);
              }
          }
      
      
      }
      

继承Thread类和Runable类的区别:

  1. 使用Runable,避免了单继承的局限性,类继承了Thread类就不能继承其他类。
  2. 增强了程序的扩建性,降低了程序的耦合性,实现了Runable将设置线程任务和开启新线程进行分离
    继承Runable接口,重写run()方法 ------》设置线程任务
    使用Thread将线程任务放进去调用start()方法 ------》设置线程任务
    使用对象注入的时候可以在配置文件中更改线程任务,不必跑到源码中修改

Jvm开启多线程的原理

  • Jvm开启线程

首先Jvm执行程序,执行到main方法时,通知OS系统开辟一条mian方法到CPU的路径,此时这条路径就称之为线程,当执行到另一个线程的start()方法时,Jvm又通知OS系统开辟一条到当前开启的线程的run()的路径,即线程。

简介版:

Jvm通知OS系统开辟一条main() -----> Cpu的线程(路径),主程序继续执行,开启另一个线程 ------->Jvm通知OS开辟一条通往开启线程run()方法的路径(线程)

  • 开启多线程时的堆栈分配

每一个线程都分配有自己的栈,公用一个堆

当一个线程停止,不影响另一个线程执行

  • 如何实现线程切换

线程的切换实际上CPU在不同线程的栈上进行切换,CPU的执行代码依赖于各种寄存器,当线程被挂起时,就将寄存器的数值放在该线程的堆中,当CPU重新执行此线程时,将从栈中取出寄存器的数值,接着运行。

CPU使用相同线程函数代码在不同的栈中切换

Thread类的常用方法

  • String getName() : 获取线程的名字

      该方法只能有一个线程实例才能使用,不能直接Thread.getName();
    
      使用情况:
    
      1.在线程的run()方法中直接调用
    
      2.通过Thread.currentThread().getName()使用
    
       因为main线程没有实现Runable和继承Thread类,因此不能直接在main方法中调用getName(),要先获取      Thread对象      
    
  • Thread currentThread() :获取当前执行线程

  • setName() :设置线程名字

  • sleep(Long millis) :设置线程睡眠时间
    该类会抛出InterrupException:中断异常
    public class SubThreadDemo02 {
    public static void main(String[] args) throws InterruptedException {
    for (int i = 0; i < 60; i++) {
    Thread.sleep(1000);
    System.out.println(i);
    }
    }
    }

使用匿名内部类创建线程

  • 什么叫匿名内部类
    即隐式的继承一个类或实现一个接口,匿名内部类是一个继承了该类或者实现了该接口的子类匿名对象。

  • 匿名内部类的分类
    继承一个类
    实现类的接口
    匿名内部类的最终产物是一个子类或实现类

    /**
     * 使用你匿名内部类来创建线程
     *匿名内部类特点:子类继承父类、重写方法、建立对象一步完成
     */
    public class RunThreadDemo03 {
        public static void main(String[] args) {
            /**
             * 创建一个继承Thread的内部类
             * 相当于一个多态,子类对象赋给父类对象使用   父类对象 = 子类对象
             */
            //1.继承父类Thread的匿名内部类
            new Thread() {
                //2.重写方法
                public void run() {
                    for (int i = 0; i < 20; i++) {
                        System.out.println(getName() + "=====" + i);
                    }
                }
                //3.创建对象,使用方法
            }.start();
    
            for (int j = 0; j < 20; j++) {
                System.out.println("main=====" + j);
            }
    
            /**
             * 创建一个实现Rununable接口的内部类
             * 使用Runnable来接收这个内部类,再放入到Thread中
             *//*
    
            Runnable r = new Runnable() {
                public void run() {
                    for (int k = 0; k < 20; k++) {
                        System.out.println(Thread.currentThread().getName() + "=====" + k);
                    }
                }
            };
            Thread th = new Thread(r);
            th.start();*/
            /**
             * 直接将匿名内部类作为参数传入
             */
            new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int k = 0; k < 20; k++) {
                        System.out.println(Thread.currentThread().getName() + "=====" + k);
                    }
                }
            }).start();
        }
    }
    

线程调度

线程的调度由jvm虚拟机实现

  • 定义
    按特定机制给多个线程分配cpu的使用
    计算机只有一个cpu,一个cpu在任意时刻只能执行一条机器指令,线程只有获取cpu的执行权才能执行指令
    并发运行的意思是线程轮流的获得cpu的使用权,在运行池中,有多个就绪状态的线程等着cpu

  • 线程调度的分类

    1. 分时调度
      所有线程轮流使用cpu且使用cpu的时间片相同
    2. 抢占式调度
      让运行池中优先级别高的线程先使用cpu,若运行池的线程级别相同则随机选择一个线程获得CPU的执行权
      处于运行状态的线程会一直运行,直至它不得不放弃CPU
  • 设置线程的优先级
    setPriority() :设置线程优先级
    getPriority() :获取线程优先级

其他

posted on 2019-08-08 19:37  宇宙美少女  阅读(481)  评论(0)    收藏  举报

导航