1、基本概念:程序、进程、线程

程序

  • 完成特定任务、用某种语言编写的一组指令的集合。一段静态的代码,静态对象。

进程

  • 程序的一次执行过程,或是正在运行的一个程序,动态的过程:产生、存在、和消亡
  • 程序是静态的,进程是动态的
  • 进程是资源分配的单位

线程

  • 线程是程序内部的一条执行路径

  • 一个进程,同一时间并行多个线程,多线程

  • 线程作为调度和执行的单位,每个线程拥有独立的运行栈和程序计数器

  • 存在安全问题

  • 一个java应用程序,至少有三个线程:main()主线程,

使用多线程的优点

  1. 提高应用程序的响应,增强用户体验
  2. 提高计算机系统CPU的利用率
  3. 改善程序结构,将复杂的进程分为多个线程,独立运行

何时需要多线程

  • 程序需要同时执行两个或多个任务
  • 程序实现一些需要等待的任务时,如:用户输入,文件读写操作、网络操作
  • 需要后台运行的程序

单核CPU和多核CPU

单核CPU

  • 假的多线程,在一个时间单元内,只能执行一个线程的任务
  • 实际上是单线程,运行中将其他进程挂起,执行,执行速度很快,所以在使用上感觉是多线程。

多核CPU

  • 真正意义上的多线程

并行与并发

  • 并行:多个CPU同时执行多个任务
  • 并发:一个CPU “同时” 执行多个任务,如:秒杀

2、线程的创建和使用

线程的创建

  • 方式一

    • 继承于Thread类

      步骤:

      1. 创建一个继承于Thread的子类
      2. 重写Thread类的run()方法--》此线程执行的操作
      3. 创建Thread类的子类对象(可使用匿名对象)
      4. 通过此对象调用start()
      5. 若要再创建新的线程,需创建新的实例来调用start()方法
      //例:遍历100以内的所有偶数
          //1.创建一个继承于Thread类的子类
      public class MyThread extends Thread{
          //2.重写Thread类的run()
          @Override
          public void run() {
              for (int i = 0; i <=1000 ; i++) {
                  if(i%2==0){
                      System.out.println(Thread.currentThread().getName()+":"+i);
                  }
              }
          }
      }
      class ThreadTest {
          public static void main(String[] args) {
              //3.创建Thread类的子类的对象
             MyThread myThread= new MyThread();
             //4.通过此对象调用start()①启动当前线程②调用当前线程的run()
             myThread.start();
              //  如下操作任然是在main()线程执行的
              for (int i = 0; i <=1000 ; i++) {
                  if(i%2!=0){
      //                Thread.currentThread().getName()获取线程名
                      System.out.println(Thread.currentThread().getName()+":"+i);
                  }
              }
          }
      }
      
      
  • 方式二

    • 实现Runnable接口

      步骤:

      1. 创建一个实现了Runnable接口的类

      2. 实现类中实现Runnable中的抽象方法:run()

      3. 创建实现类的对象

      4. 将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象

      5. 通过Thread类的对象调用start()

        //1. 创建一个实现了Runnable接口的类
         class MIThread implements Runnable{
        //     2. 实现类中实现Runnable中的抽象方法:run()
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    if(i%2==0){
                        System.out.println(Thread.currentThread().getName()+":"+i);
                    }
                }
            }
        }
        class ThreadTes{
            public static void main(String[] args) {
        //        3. 创建实现类的对象
              MIThread mi=  new MIThread() ;
        //        4. 将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
              Thread t1=new Thread(mi);
        //        5. 通过Thread类的对象调用start(),启动当前线程,调用当前线程的run方法,底层是Thread含有Runnable类型参数的构造器
              t1.start();
        //      再启动一个线程
                Thread t2=new Thread(mi);
                t2.start();
            }
        }
        
  • 比较两种创建方式

    • 开发中优先选择,实现Runnable接口的方式

    • 原因:

      1. 实现的方式没有类的单继承的局限
      2. 实现方式更适合处理多线程有共享数据的情况
    • 联系: public class Thread implements Runnable

      相同点:两种方式都需要重写run() 将线程 要执行的逻辑声明在run()中;

线程的调度

  • 调度策略
    • 时间片
    • 抢占式,高优先级的线程抢占CPU
  • java的调度方法
    • 先来先服务,先进先出队列
    • 高优先级,优先调度的抢占式策略

线程优先级

  • 优先级

    • MAX_PRIORITY : 10
    • MIN_PRIORITY: 1
  • NORM_PRIORITY : 5

  • 获取和设置当前线程的优先级

    • getPriority()
    • setPriority( int p)
  • 高优先级的线程要抢占低优先级线程的CPU执行权,只是从概率上讲,高优先级有很高概率会执行,但并不意味着高优先级的线程执行完,低优先级的才执行;

3、线程的生命周期

线程生命周期的五种状态

  • 新建:Thread类或子类对象被声明创建时

  • 就绪:新建的线程被start()后,获取了其他所有的资源,只是没分配到CPU资源

  • 运行:获取CPU资源,执行

  • 阻塞:某种特殊情况下,让出CPU并临时终止自己的执行

  • 死亡:完成它的全部工作或线程提前被强制性的终止,异常导致结束;

  • 状态图

内容来源于网络如有侵权请私信删除

文章来源: 博客园

原文链接: https://www.cnblogs.com/codehan/p/14630133.html

你还没有登录,请先登录注册
  • 还没有人评论,欢迎说说您的想法!