Java EE|多线程基本操作

news2024/10/5 13:33:56

文章目录

    • 一、一个简单的线程程序及运行
    • 二、线程的创建
    • 三、线程类——Thread详解
      • 常见构造方法
      • 常见几个属性
      • 线程的启动——start()
      • 线程的中断
      • 线程的等待——join()
      • 线程引用的获取
      • 线程的休眠
    • 四、多线程编程效率举例

一、一个简单的线程程序及运行

在写这样一个代码之前,我们需要对Thread类有一个简单/感性的认识

我们已经知道进程是OS进行资源分配的基本单位,线程是OS进行调度的基本单位。也就是说其实进程和线程都是基于操作系统的概念。又因为app的运行需要OS进行协助,所以,app中必须要有针对进程和线程的处理,而OS中也必须有关于对app发送过来的这些信息进程接收和加工,从而启动硬件,完成我们的任务。

简而言之,就是说OS和app之间需要有一个类似API一样的东西进行联系。但其实并不是一个就可以。因为我们经常会有这样的需求:不同的OS上运行相同的app;相同的OS上运行不同的app。

因此,实际上,我们的OS会提供一套这样的类库,每个app又会提供一套用于连接OS的类库,不同的OS上对应的app类库不同。

举个例子:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GcIhP2et-1669768479691)(F:\typora插图\image-20221128125953291.png)]

Thread 类是 JVM 用来管理线程的一个类。每个线程都有一个唯一的 Thread 对象与之关 联。

另外,Thread类是一个实现了Runnable接口的类,其中这个线程跑起来就是靠的这个接口中run方法。但是这个跑是在后台跑,我们并不能看到明显的效果,因此为了看到效果,我们需要重写run方法。这里我们采用的是继承Thread类重写run方法。

方法被调用了线程才能跑起来,怎么调用呢?这里用到的了Thread类对象的start方法。具体我会在后边讨论。也可以说只有start方法被调用了,这个线程才算创建成功了。

复盘一下,怎么样才算创建好一个线程呢?

①MyThread类继承Thread类,重写run方法②调用start方法

下边我们就来,写一下程序。

class MyThread extends Thread{
    @Override
    public void run() {
        for(int i=0;i<100;i++){
            System.out.println("子线程:hello world");
        }
    }
}
public class ThreadDemo1 {
    public static void main(String[] args) {
        Thread t1=new MyThread();
        Thread t2=new MyThread();

        t1.start();
        t2.start();

        for(int i=0;i<100;i++){
            System.out.println("主线程:hello");
        }
    }
}

(不完全运行截图)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aHApEXQw-1669768479693)(F:\typora插图\image-20221128115426831.png)]

除了程序运行结果,我们还可以通过jdk提供的线程的观察工具——jconsole.exe,观察线程。

具体使用方法是:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6cYrRmL6-1669768479694)(F:\typora插图\image-20221129092415580.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MmxsxXOX-1669768479695)(F:\typora插图\image-20221129090456698.png)]

当然除了上述方法我们还可以通过下边这种方式进行观察:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DX8Xytkx-1669768479696)(F:\typora插图\image-20221129093105948.png)]

此时,我们的一个简单的线程程序就写好了。

下边,我们来讨论几个问题:

1.主线程&子线程

1.什么是主线程?什么是子线程?

当一个程序启动时,就有一个进程被OS创建,同时进程中的某个线程也立即运行。这个线程就叫做主线程。

子线程就是由其他线程所创建的线程。包括主线程但不仅限于主线程。

2.主线程的重要性

(1)是产生其他子线程的线程

(2)它通常需要最后完成执行

补充:

main方法执行完了,主线程也就完了;同理,run方法完了,子线程也就完了。

这里边的t1、t2、t3都是子进程、main是主进程。

2.主线程和子线程的执行顺序

由于线程抢占式执行的特点,使得线程调度也具有随机性。即使代码时固定的。

因此,不同线程的执行顺序是不可预估的,具有随机性。

这是由OS内核实现决定的。

3.多线程程序和普通程序有什么区别

  • 每个线程都是一个独立的执行流
  • 多个线程之间是“并发”执行的。
  • 代码固定,执行顺序不一定固定

虽然我们这里说是创建一个线程,但其实这个程序整体本质上还是一个多线程程序,main是一个主线程,创建的子线程包裹在主线程下。


二、线程的创建

上边我们已经写了一个简单的多线程程序,但线程的创建方法远不止一种。基本上有三种,另外还有两种基于此的拓展。

方法一:继承Thread类

class MyThread extends Thread{
    @Override
    public void run() {
        for(int i=0;i<100;i++){
            System.out.println("子线程:hello world");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
public class ThreadDemo1 {
    public static void main(String[] args) {
        Thread t1=new MyThread();
        t1.start();
        for(int i=0;i<100;i++){
            System.out.println("主线程:hello");
        }
    }
}

方法二:实现Runnable接口

public class ThreadDemo2 {
    class MyThread implements Runnable{
        @Override
        public void run() {
            System.out.println("hello world");
        }
    }

    public static void main(String[] args) {
        Thread t=new thread.MyThread();
        t.start();
        System.out.println("hello");
    }
}

方法三:匿名内部类创建Thread子类对象

public class ThreadDemo3 {
    public static void main(String[] args) {
        Thread t=new Thread(){
            @Override
            public void run() {
                System.out.println("hello world");
            }
        };
        t.start();
        System.out.println("hello");
    }
}

方法四:匿名内部类创建Runnable子类对象

public class ThreadDemo4 {
    public static void main(String[] args) {
        Thread t=new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello world");
            }
        });
        t.start();
        System.out.println("hello");
    }
}

方法五:lambda表达式创建Runnable子类对象【用的比较多】

public class ThreadDemo5 {
    public static void main(String[] args) {
        Thread t=new Thread(()-> System.out.println("hello world"));
        t.start();
        System.out.println("hello");
    }
}

三、线程类——Thread详解

每个执行流,需要有一个对象来描述,而 Thread 类的对象 就是用来描述一个线程执行流的,JVM 会将这些 Thread 对象组织起来,用于线程调度,线程管理。

是java.lang包下的==>不需要导包

常见构造方法

方法说明
Thread()创建对象
Thread(Runnable target)使用Runnable对象创建线程对象
Thread(String name)创建线程对象并命名
Thread(Runnable target,String name)使用Runnable对象创建线程对象并命名
Thread(ThreadGroup group,Runnable target)创建到指定线程组下

假如我们起名字mythread,那么通过jconsole观察到的线程名就是mythread,而我们在代码中的t是代码中的变量名

常见几个属性

常见属性有id、名称、状态、优先级,但是由于都是私有类型的,所以必须要有对应方法才能访问到,除此以外还需判断几个特性比如是否存在,是否是后台线程,是否被中断。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-evYZYUAu-1669768479696)(F:\typora插图\image-20221128134356160.png)]

属性获取方法
idgetId()
名称getName()
状态getState()
优先级getPriority()
是否是后台程序isDaemon()
是否存活isAlive()
是否被中断isInterrupted

其中:

  • id,线程的唯一标识,不同线程id不同。只能get,不能set.

  • 名称,就是我们在构造方法中起的名字,在各种调试工具会用到。可set可get。get通过getName()方法得到,set通过Thread构造方法设置。

  • 状态,表示当前线程所处的状态,下一篇会详细讨论(java中线程的状态会比OS原生状态更丰富一些)

  • 优先级高的线程理论上 更容易被调度到。但基本上没啥用,影响因素太多。

  • 后台进程:也就是守护线程。JVM会在一个进程的所有非后台进程结束后,才会结束运行

    我们这里结合前台线程解释后台线程。

    前台线程,会组织进程结束,前台线程没做完,进程完不了;

    后台线程,不会组织进程结束,后台线程工作没做完,进程也可以结束。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UNRf6OFv-1669768479697)(F:\typora插图\image-20221128143715204.png)]

    易错:线程(都是死循环)调度过程中的交替打印和线程是前台和后台没有关系。是前台和是后台只跟setDaemon的设置有关。

    思考:JVM进程什么退出?

    1.所有的前台线程全部退出

    2.与主线程无关,主线程的退出不影响

  • 是否存活:判断OS中线程是否存活也就是run方法是否运行结束

    t的回收:没有被引用,就会被GC回收。

    GC:(垃圾回收( Garbage Collection )是一种自动管理内存的机制)

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oniz2T4Y-1669768479698)(F:\typora插图\image-20221128145629476.png)]

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bAkcHQDI-1669768479698)(F:\typora插图\image-20221128150725440.png)]

  • 线程中断问题,下边会详细讨论

线程的启动——start()

调用start方法,才会真正在OS底层创建出一个线程。

run方法和start方法功能对比:

run方法:描述了线程要做的工作

start方法:真正在OS内核中创建了一个线程,并且让这个线程调用run方法

线程的中断

此处中断的含义:让当前线程停止执行。【不要和OS中的中断弄混】

注意:中断的意思不是让线程立即就停止,而是给线程发送一个通知,你要停止了,但是否真的停止,取决于线程具体的实现

线程的中断常见的有两种方式

(1)通过共享的标记来进行沟通

public class ThreadDemo6 {
    public static boolean flag=true;

    public static void main(String[] args) {
        Thread t=new Thread(()-> {
            while(flag){
                System.out.println("hello world");
            }
        });
        t.start();
        //在主线程中可以随时通过flag变量的取值,来操作t线程是否结束
        flag=false;
    }
}

(2)调用interrupt方法进行通知【用的更多些】

这里是用的Thread自带的标志位进行中断。这个东西可以唤醒上边的sleep

public class ThreadDemo7 {
    public static boolean flag=true;

    public static void main(String[] args) {
        Thread t=new Thread(()-> {
            while(!Thread.currentThread().isInterrupted()){
                System.out.println("hello world");
            }
        });
        t.start();
        t.interrupt();
    }
}

currentThread方法:是Thread类的静态方法,通过这个方法可以获得当前线程,哪个线程调用这个方法,就得到哪个线程的引用,类似于this引用。

isInterrupted方法:是在t.run中被调用的,这里获取的线程就是t线程。结果为true就是表示被终止,为false就是表示没有被终止(需要继续执行)。

interrupt方法:就是终止线程。这里t.interrupt()就是终止t线程。这里是在main方法中,也就是主线程通知子线程,它需要中断了,

方法说明
public void interrupt()中断对象关联的线程,如果线程正在阻塞/sleep,就以异常方式通知,否则设置标志位,变成true
public static boolean interrupted()(少)判断当前线程的中断标志位是否设置,调用后清除标志位
public boolean isinterrupted()判断对象关联的线程的标志位是否设置,调用后不清楚标志位

思考:“如果线程正在阻塞,就以异常方式通知,否则设置标志位,变成true”这句话怎么理解呢?

  1. 此时interrupt触发sleep内部的异常,导致sleep提前返回。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pMm1oWrJ-1669768479698)(F:\typora插图\image-20221128154633191.png)]

  1. sleep被唤醒之后,又会把标志位设回false

    public class ThreadDemo8 {
        public static void main(String[] args) throws InterruptedException {
            Thread t=new Thread(()-> {
                while(!Thread.currentThread().isInterrupted()){
                    System.out.println("hello world");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
            t.start();
            Thread.sleep(1000);
            t.interrupt();
        }
    }
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-d02J15vP-1669768479699)(F:\typora插图\image-20221128155307369.png)]


特别注意:sleep存在时的线程中断

interrupt做的事情:

  1. 线程内部的标志位会设置成true
  2. 线程若在sleep,会出发异常,把sleep唤醒

sleep被唤醒之后做的事情:

​ 把刚刚设置的标志位,再设回false(清空标志位)

效果:当sleep的异常被catch完后,循环还要继续执行

这也就说明了,我们上边为什么说是通知它终止,而不是它一定终止。除此以外,sleep被唤醒之后,还有其他处理方式。下边我们来总结一下。

(1)忽略中断请求

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xeRwXVy0-1669768479699)(F:\typora插图\image-20221128160804926.png)]

(2)立即响应中断请求【加了break】

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HnM4m5IV-1669768479700)(F:\typora插图\image-20221128160832793.png)]

(3)稍后进行中断【中间加了其他代码(任何)】

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FemsuNGD-1669768479701)(F:\typora插图\image-20221128160933166.png)]

也就是说我们可以通过清除标志位之后的操作来决定线程t如何对待我们的中断请求。

与之类似的是,像wait、join等造成代码“暂停”的方法都会有类似的清除标志位的设定。


线程的等待——join()

线程的等待就是等待一个线程结束。

由于抢占式执行,我们无法判定两个线程谁先开始,但是我们可以通过调用join方法决定谁先结束。

方法说明
public void join()等待线程结束。如果仍未结束,那么就等待;反之立即返回
public void join(long miles)等待线程结束,最多等miles秒
public void join(long miles,int nanos)第二个的plus版本,体现在精度更高上

其中这里的nanos是纳秒单位

下边我们针对第一个join方法来举个例子:

public class ThreadDemo8 {
    public static void main(String[] args) {
        Thread t=new Thread(()-> {
                System.out.println("hello world");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
        });
        t.start();
        System.out.println("join之前");
        try {
            //此时的join就是让当前的main线程等待t线程执行完再,继续执行
            //此时main线程走到这里就停止了,我们称为它被阻塞了
            //此时一定达到一个目的————t线程先于main线程结束
            System.out.println();
            t.join();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("join之后");
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YerqEJP7-1669768479702)(F:\typora插图\image-20221128163344101.png)]

上述情况是,执行join时,t仍未结束,那么main线程就会阻塞;

但如果join不阻塞,main线程不会阻塞,会立即返回。

相对于第一种,第二种使用的更多。第一种没有参数,相当于“死等”。第二种是指定一个最长等待时间,超过一定时间,不再等。

而第三种,是第二种的plus版,其中nano是纳的意思,也就是说多少毫秒多少纳秒更加精准罢了。

线程引用的获取

方法说明
public static Thread currentThread()返回当前线程的引用

类似this引用,比较“智能”。哪个线程调用,就是哪个线程的引用。

线程的休眠

方法说明
public static void sleep(long miles) throws InterruptedException休眠当前线程miles毫秒
public static void sleep(long miles,int nanos) throws InterruptedException可以更高精度休眠

四、多线程编程效率举例

一般而言,程序分成使用cpu密集即需要大量运算和io密集即读写文件密集。

我们之前一直在说多线程编程优于多进程编程,但是那只是理论上,我们并没有直观的感受。

下边我们通过单线程和多线程实现对a和b分别自增100w次效率对比 ,来直观感受一下。

public class ThreadDemo9 {
    public static void main(String[] args) {
        //serial();//串行耗时
        concurrency();//并行耗时
    }
    public static void serial(){
        long start=System.currentTimeMillis();
        long a=0;
        long b=0;
        for (long i = 0; i <100_0000_0000L; i++) {
            a++;
        }
        for (long i = 0; i <100_0000_0000L; i++) {
            b++;
        }
        long end=System.currentTimeMillis();
        System.out.println("执行时间:"+(end-start)+"ms");
    }
    public static void concurrency(){
        Thread t1=new Thread(()-> {
            long a=0;
            for (long i = 0; i <100_0000_0000L; i++) {
                a++;
            }
        });
        Thread t2=new Thread(()-> {
            long b=0;
            for (long i = 0; i <100_0000_0000L; i++) {
                b++;
            }
        });
        long start=System.currentTimeMillis();
        t1.start();
        t2.start();
        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        long end=System.currentTimeMillis();
        System.out.println("执行时间:"+(end-start)+"ms");
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FhUnxu4s-1669768479703)(F:\typora插图\image-20221128172121448.png)]

接下来,我们讨论几个问题:

  1. 为什么两个线程的结果不是一个线程耗时的一半?

    线程的切换需要时间、不能保证两个线程总是并行执行,即使是cpu是多核的。

  2. 为什么要join?

    线程调度是随机的,如果不join,有可能a和b都还没有完成全部的自增任务,就已经结束了。

  3. start和end的定义时机特别注意

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/47492.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

web框架

目录 1 左右分割窗口 2 上下分割窗口 3 嵌套分割窗口 4 内联框架 框架的作用是把浏览器窗口划分成若干个小窗口&#xff0c;每个小窗口可以分别显示不同的网页。 框架的基本结构主要分为框架集和框架两个部分&#xff0c;在网页中分别用<frameset>和<frame>标记…

Netty进阶——粘包与半包(代码示例)

目录一、消息粘包和消息半包的概述1.1、消息粘包1.2、消息半包二、粘包现象代码示例2.1、粘包现象服务端示例代码2.2、粘包现象客户端示例代码2.3、分别启动服务端&#xff0c;客户端&#xff0c;查看服务端结果输出三、半包现象代码示例3.1、半包现象服务端示例代码3.2、半包现…

【JavaSE】学习异常

前言&#xff1a; 作者简介&#xff1a;爱吃大白菜1132 人生格言:纸上得来终觉浅&#xff0c;绝知此事要躬行 如果文章知识点有错误的地方不吝赐教&#xff0c;和大家一起学习&#xff0c;一起进步&#xff01; 如果觉得博主文章还不错的话&#xff0c;希望三连支持&#xff01…

D-020 SPI FLASH硬件电路设计

SPI FLASH硬件电路设计1 简介2 EEPROM 和SPI Flash的区别3 电路设计实战4 电路设计要点1 简介 SPI FLASH(Serial Peripheral Interface)是串行外设接口的缩写&#xff0c;是一种高度、全双工、同步的通信总线。一般应用在MCU与外围设备之间通讯&#xff0c;广泛应用在FLASH&am…

从模型容量的视角看监督学习

这几天看离线强化学习瞎想的&#xff0c;不一定正确&#xff0c;仅记录个人想法 文章目录1. 监督学习的本质2. 容量视角下的模型选择、正则化和归纳偏置3. 几点启发1. 监督学习的本质 我认为监督学习的本质在于在过拟合和欠拟合之间取得平衡&#xff0c;捋一下逻辑 我们知道&a…

基于JAVA+SpringMVC+Mybatis+Vue+MYSQL的医药销售管理系统

项目介绍 药品一直以来在人类生活中扮演着非常重要的角色&#xff0c;随着时代的飞速发展&#xff0c;人们基本已经告别了那个缺医少药的年代&#xff0c;各大药房基本随处都可以购买&#xff0c;但是很多时候因为没有时间或者在药店很难找到自己想要购买的药品&#xff0c;所…

[附源码]计算机毕业设计springboot个人博客系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

Windows远程连接centos7图形化界面,安装xrdp

Windows远程连接centos7图形化界面&#xff0c;安装xrdp写在最前面准备工作查看ubuntu系统的版本信息和gcc版本尝试进入图形化界面更新yum下载安装图形化界面查询本地是否有Server with GUI group安装Server with GUI设置系统启动默认加入GUI界面安装epel库&#xff08;epel是社…

Djiango 模版系统详解(ORM数据模型-使用mysql数据库增删改查)

djiango模版系统&#xff1a; 用于自动渲染一个文本文件&#xff0c;一般用于HTML页面&#xff0c;模版引擎渲染的最终HTML内容返回给客户端浏览器 模版系统分成两部分 静态部分&#xff1a; 例如html css .js 动态部分 djiango 模版语言&#xff0c;类似于jinja语法变量定义&…

ArcGIS QGIS学习二:图层如何只显示需要的部分几何面数据(附最新坐标边界下载全国省市区县乡镇)

文章目录前言准备SHP数据ArcMap 的筛选QGIS 的筛选如何编写查询条件前言 当我们用GIS软件打开一个SHP文件的时候&#xff0c;会显示出里面全部的几何图形&#xff0c;假如我只想要其中的一部分数据显示出来&#xff0c;其他的均不要显示&#xff0c;有那么几种操作方法。 我们…

UE4使用蓝图实现角色冲刺

又学了几天&#xff0c;前面记录了如何使用蓝图实现开关门&#xff0c;这次来实现一下角色的冲刺、瞬移的操作 一般玩游戏的时候&#xff0c;可能都会有按左shift键让角色从行走变成奔跑的状态&#xff0c;又或者双击回避键角色瞬移躲避等操作 那就先实现一下加速奔跑吧&…

Python毕业设计必备案例:【学生信息管理系统】

嗨害大家好鸭&#xff01;我是小熊猫~ 最近看大家好像都快放假啦~ 但是放假之前有的小朋友要做毕业设计~ 有的要期末考试~ 那么今天来给大家整一个小的毕业管理系统案例 康康整题思路是怎么样的~ 源码、资料电子书点击这里获取 功能模块 基本信息管理和学生成绩管理。 基…

【自用】VUE 获取登录用户名 显示在其他页面上

大步骤一、准备工作 步骤1&#xff1a; 安装 js-cookie 依赖 npm install js-cookie --save步骤2&#xff1a; 在登录页面中引入 js-cookie 依赖 <script> import jsCookie from js-cookie; </script>大步骤二、在 登录页面 的vue文件 中使用它&#xff01; …

[附源码]计算机毕业设计springboot基于JAVA技术的旅游信息交互系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

[附源码]Python计算机毕业设计SSM泸定中学宿舍管理系统设计(程序+LW)

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

python零基础入门(完整版)

1python软件下载 我们需要下载python语言翻译器&#xff08;也就是运行环境&#xff09;&#xff0c;和一个用来写python的软件&#xff0c;用它写python语言比较方便 首先打开百度&#xff0c;下载org 然后点击下载 然后选择一个稳定版本下载 然后会跳转到一个页面&#xff0c…

kubernetes-service详解

kubernetes-service详解 文章目录kubernetes-service详解一、Service操作一&#xff1a;创建集群内部可访问的Service操作二&#xff1a;创建集群外部也可访问的Service二、pod详解pod的资源清单pod 配置基本配置镜像拉取启动命令环境变量端口配置资源配额一、Service 虽然每个…

NumPy 数组应用初探

NumPy是Python中科学计算的基本包。它是一个Python库&#xff0c;提供了一个多维数组对象&#xff0c;各种派生对象&#xff08;如屏蔽数组和矩阵&#xff09;&#xff0c;以及对数组进行快速操作的各种例程&#xff0c;包括数学、逻辑、形状操作、排序、选择、I/O、离散傅立叶…

Python-可视化单词统计词频统计中文分词

可视化单词统计词频统计中文分词项目架构新建文件单词计数全文单词索引中文分词统计词频源代码项目架构 新建一个文件&#xff0c;输入文件的内容&#xff0c;查询此文件中关键字的出现的次数&#xff0c;关键字出现的位置&#xff0c;将所有的文本按照中文分词的词库进行切割…

运筹说 第76期 | 最短路问题

通过前面的学习&#xff0c;我们已经学会了图与网络问题中图的基本概念和最小树问题&#xff0c;本期小编带大家学习最短路问题。 一 最短路问题 最短路问题是网络理论中应用最广泛的问题之一。许多优化问题可以使用这个模型&#xff0c;如设备更新、管道敷设、线路安排、厂区…