• day31-线程基础01


    🚀 优质资源分享 🚀

    学习路线指引(点击解锁)知识定位人群定位
    🧡 Python实战微信订餐小程序 🧡进阶级本课程是python flask+微信小程序的完美结合,从项目搭建到腾讯云部署上线,打造一个全栈订餐系统。
    💛Python量化交易实战💛入门级手把手带你打造一个易扩展、更安全、效率更高的量化交易系统

    线程基础01

    1.程序 进程 线程

    • 程序(program):是为完成的特定任务,用某种语言编写的一组指令的集合。简单来说,就是我们写的代码。

    image-20220903181710298

    • 进程:

      1. 进程是指运行中的程序,比如我们使用QQ,就启动了一个进程,操作系统就会为该进程分配空间。当我们使用迅雷,又启动了一个进程,操作系统将为迅雷分配新的内存空间。
      2. 进程是程序的一次执行过程,或是正在运行的一个程序。是动态过程:有它自身的产生、存在和消亡的过程。image-20220903182817371
    • 线程:

      1. 线程是由进程创建的,是进程的一个实体
      2. 一个进程可以有多个线程,比如:用迅雷同时下载多个文件
    • 其他相关概念:

      1. 单线程:同一时刻,只允许执行一个线程
      2. 多线程:同一时刻,可以执行多个线程,比如:一个qq进程,可以同时打开多个聊天窗口;一个迅雷进程,可以同时下载多个文件。
      3. 并发:同一时刻,多个任务交替执行,造成一种“貌似同时”的错觉,简单地说,单核cpu实现的多任务就是并发image-20220903183757457
      4. 并行:同一时刻,多个任务同时执行。多核cpu可以实现并行。在电脑中也可能同时出现并发和并行的状态。

    image-20220903183821311

    例子:

    
    
    |  | package li.thread; |
    |  |  |
    |  | public class CpuNum { |
    |  | public static void main(String[] args) { |
    |  |  |
    |  | Runtime runtime = Runtime.getRuntime(); |
    |  | //获取当前的电脑的cpu数量 |
    |  | int cpuNums = runtime.availableProcessors(); |
    |  |  System.out.println("当前的CPU数量="+cpuNums);//当前的CPU数量=8 |
    |  |  |
    |  |  } |
    |  | } |
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    2.线程的基本使用

    • 创建线程的两种方式

    在java中线程来使用有两种方法:

    1. 继承Thread类,重写run方法
    2. 实现Runnable接口,重写run方法

    image-20220903191317462

    2.1继承Thread创建线程

    例子1:线程应用案例1-继承Thread类

    1)请编写程序,开启一个线程,该线程每隔一秒,在控制台输出 “喵喵,我是小猫咪”

    2)对上题改进:当输出80次“喵喵,我是小猫咪”时,结束该线程

    3)使用JConsole监控线程执行情况,并画出程序示意图

    
    
    |  | package li.thread; |
    |  |  |
    |  | //演示通过继承Thread类创建线程 |
    |  | public class Thread01 { |
    |  | public static void main(String[] args) throws InterruptedException { |
    |  |  |
    |  | //创建一个Cat对象,可以当做线程来使用 |
    |  | Cat cat = new Cat(); |
    |  |  |
    |  |  cat.start();//启动线程 |
    |  |  |
    |  | //当main线程启动一个子线程 Thread-0后,主线程不会阻塞,会继续执行 |
    |  | //这时 主线程和子线程是交替执行 |
    |  |  System.out.println("主线程继续执行="+Thread.currentThread().getName());//主线程继续执行=main |
    |  | for (int i = 0; i < 60; i++) { |
    |  |  System.out.println("主线程 i="+i); |
    |  | //让主线程休眠 |
    |  |  Thread.sleep(1000); |
    |  |  } |
    |  |  } |
    |  | } |
    |  |  |
    |  | //1.当一个类继承了Thread类,该类就可以当做一个线程使用 |
    |  | //2.我们会重写run方法,写上自己的业务代码 |
    |  | //3.run Thread类实现了Runnable接口的run方法 |
    |  | /* |
    |  |  @Override |
    |  |  public void run() { |
    |  |  if (target != null) { |
    |  |  target.run(); |
    |  |  } |
    |  |  } |
    |  |  */ |
    |  | class Cat extends Thread { |
    |  | @Override |
    |  | public void run() {//重写run方法,写上自己的业务逻辑 |
    |  | int times = 0; |
    |  | while (true) { |
    |  | //该线程每隔1秒,在控制台输出 “喵喵,我是小猫咪” |
    |  |  System.out.println("喵喵,我是小猫咪" + (++times)+" 线程名称="+Thread.currentThread().getName()); |
    |  | //让该线程休眠一秒 |
    |  | try { |
    |  |  Thread.sleep(1000);//单位为毫秒 try-catch快捷键:Ctrl+Alt+T |
    |  |  } catch (InterruptedException e) { |
    |  |  e.printStackTrace(); |
    |  |  } |
    |  | if (times == 80) { |
    |  | break;//当times到80,退出while,这是线程也就退出了 |
    |  |  } |
    |  |  } |
    |  |  } |
    |  | } |
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

    3)使用JConsole监控线程执行情况,并画出程序示意图:

    如下,在控制台点击run,运行程序,在程序运行时,点击Termial

    image-20220903201816455
    在控制台输入JConsole,回车。

    image-20220903201903908
    点击本地进程,点击Thread01,点击下方连接按钮:

    image-20220903202032834
    在弹出窗口中点击不安全的连接按钮:

    image-20220903202109982
    在窗口中点击“线程”:

    image-20220903202616380
    可以在左下角的线程小窗口中看到main线程和Thread-0线程在同时进行

    image-20220903202808116
    等待一段时间,可以看到当run窗口的主线程 i = 60之后,main线程结束

    结束前:

    image-20220903203153344
    结束后:image-20220903203145376

    当线程名称=Thread-0输出到80次时,虽然可以Thread-0还在左下角,但是实际上Thread-0线程已经结束了,整个进程随之结束。

    image-20220903204614562
    程序示意图:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7GcHdoWc-1662225042162)(https://liyuelian.oss-cn-shenzhen.aliyuncs.com/imgs/%E7%BA%BF%E7%A8%8B%E7%9A%84%E5%9F%BA%E6%9C%AC%E4%BD%BF%E7%94%A8.png)]

    注意:在多线程编程里面,并不一定说主线程结束了,整个进行就结束了,等所有线程都结束了,进程才会结束。

    2.2为什么是start?

    在2.1的例子中,主方法中定义了cat对象,该对象调用了start方法,start方法会去启动一个线程,最终会执行Cat 类的run方法。

    思考一个问题:既然最终都是要调用run方法,为什么cat对象还要通过start方法对调用run呢?为什么不直接调用?

    答案: 首先通过 对象.run() 方法 可以执行方法,但是不是使用的多线程的方式,就是一个普通的方法,没有真正地启动一个线程。即这时候把run方法执行完毕,才能执行主方法剩下的语句。

    如下图:将cat.start();改为cat.run();之后的运行结果:

    在run方法执行完之后才执行主方法剩下的语句

    image-20220903213334214


    那么在调用start方法时,整个过程到底是什么样子的?

    点击start()方法:可以在start方法中看到一个start0()方法:

    image-20220903213931518
    点击start0( )方法:可以看到start0是一个本地方法,由 JVM调用,底层是c/c++实现。

    image-20220903214152774
    再看看run()方法的源码:可以看到run方法只是简单的调用了实现类的run,没有进行任何的多线程处理。

    image-20220903215311977
    换而言之,Java中真正实现多线程的效果的是start0方法,而不是run方法

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mYXqC6Fn-1662225042167)(https://liyuelian.oss-cn-shenzhen.aliyuncs.com/imgs/start0%E6%96%B9%E6%B3%95.png)]

  • 相关阅读:
    MIT6.830-lab5-B+ Tree Index(数据库的索引B+树的搜索、插入、删除窃取、删除合并)
    初识数据结构——时间复杂度
    LeetCode ❀ 35.搜索插入位置 / python实现二分法
    自动驾驶感知算法实战14——感知算法模型生产线
    会员通?会员通!
    【译】.NET 7 中的性能改进(五)
    加州大学伯克利分校 计算机科学专业
    Qt 创建包含多个项目的工程以及各项目之间的调用
    Java线程休眠与中断
    9、动态SQL
  • 原文地址:https://blog.csdn.net/qq_43479892/article/details/126684868