多 线 程

1.什么是多线程?
有了多线程,我们就可以让程序同时做多件事情
2.多线程的作用?
提高效率
3.多线程的应用场景?
只要你想让多个事情同时运行就需要用到多线程
比如:软件中的耗时操作、所有的聊天软件、所有的服务器

1.进程和线程【理解】

  • 进程:是正在运行的程序

    独立性:进程是一个能独立运行的基本单位,同时也是系统分配资源和调度的独立单位 动态性:进程的实质是程序的一次执行过程,进程是动态产生,动态消亡的 并发性:任何进程都可以同其他进程一起并发执行

  • 线程:是进程中的单个顺序控制流,是一条执行路径

    单线程:一个进程如果只有一条执行路径,则称为单线程程序

    多线程:一个进程如果有多条执行路径,则称为多线程程序

2.并发和并行【理解】

  • 并发:在同一时刻,有多个指令在单个CPU上交替执行

  • 并行:在同一时刻,有多个指令在多个CPU上同时执行。

3.多线程的实现方式

  1. 继承Thread类的方式进行实现
  2. 实现Runnable接口的方式进行实现
  3. 利用Callable接口和Future接口方式实现

4.实现多线程方式一:继承Thread类【应用】

  1. 方法介绍

    方法名说明
    void run()在线程开启后,此方法将被调用执行
    void start()使此线程开始执行,Java虚拟机会调用run方法()
  2. 实现步骤

    1. 定义一个类MyThread继承Thread类

    2. 在MyThread类中重写run()方法

    3. 创建MyThread类的对象

    4. 启动线程

  3. 代码演示
public class MyThread extends Thread{

    @Override
    public void run() {
        //书写线程要执行代码
        for (int i = 0; i < 100; i++) {
            System.out.println(getName() + "HelloWorld");
        }
    }
}
public class ThreadDemo {
    public static void main(String[] args) {
        /*
        * 多线程的第一种启动方式:
        *   1. 自己定义一个类继承Thread
        *   2. 重写run方法
        *   3. 创建子类的对象,并启动线程
        * */


        MyThread t1 = new MyThread();
        MyThread t2 = new MyThread();

        t1.setName("线程1");
        t2.setName("线程2");

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

    }
}

两个小问题

  • 为什么要重写run()方法?

    因为run()是用来封装被线程执行的代码

  • run()方法和start()方法的区别?

    run():封装线程执行的代码,直接调用,相当于普通方法的调用

    start():启动线程;然后由JVM调用此线程的run()方法

5实现多线程方式二:实现Runnable接口【应用】

  • Thread构造方法

    方法名说明
    Thread(Runnable target)分配一个新的Thread对象
    Thread(Runnable target, String name)分配一个新的Thread对象
  • 实现步骤

    • 定义一个类MyRunnable实现Runnable接口

    • 在MyRunnable类中重写run()方法

    • 创建MyRunnable类的对象

    • 创建Thread类的对象,把MyRunnable对象作为构造方法的参数

    • 启动线程

代码演示

public class MyRun implements Runnable{

    @Override
    public void run() {
        //书写线程要执行的代码
        for (int i = 0; i < 100; i++) {
            //获取到当前线程的对象
            /*Thread t = Thread.currentThread();
            System.out.println(t.getName() + "HelloWorld!");*/
            System.out.println(Thread.currentThread().getName() + "HelloWorld!");
        }
    }
}
public class ThreadDemo {
    public static void main(String[] args) {
        /*
         * 多线程的第二种启动方式:
         *   1.自己定义一个类实现Runnable接口
         *   2.重写里面的run方法
         *   3.创建自己的类的对象
         *   4.创建一个Thread类的对象,并开启线程
         * */


        //创建MyRun的对象
        //表示多线程要执行的任务
        MyRun mr = new MyRun();

        //创建线程对象
        Thread t1 = new Thread(mr);
        Thread t2 = new Thread(mr);

        //给线程设置名字
        t1.setName("线程1");
        t2.setName("线程2");


        //开启线程
        t1.start();
        t2.start();





    }
}

6.实现多线程方式三: 实现Callable接口【应用】

  • 方法介绍

    方法名说明
    V call()计算结果,如果无法计算结果,则抛出一个异常
    FutureTask(Callable<V> callable)创建一个 FutureTask,一旦运行就执行给定的 Callable
    V get()如有必要,等待计算完成,然后获取其结果
  • 实现步骤

    1. 定义一个类MyCallable实现Callable接口

    2. 在MyCallable类中重写call()方法

    3. 创建MyCallable类的对象

    4. 创建Future的实现类FutureTask对象,把MyCallable对象作为构造方法的参数

    5. 创建Thread类的对象,把FutureTask对象作为构造方法的参数

    6. 启动线程

    7. 再调用get方法,就可以获取线程结束之后的结果。

  • 代码演示

import java.util.concurrent.Callable;

public class MyCallable implements Callable<Integer> {

    @Override
    public Integer call() throws Exception {
        //求1~100之间的和
        int sum = 0;
        for (int i = 1; i <= 100; i++) {
            sum = sum + i;
        }
        return sum;
    }
}


import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class ThreadDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {

            /*
            *   多线程的第三种实现方式:
            *       特点:可以获取到多线程运行的结果
            *
            *       1. 创建一个类MyCallable实现Callable接口
            *       2. 重写call (是有返回值的,表示多线程运行的结果)
            *
            *       3. 创建MyCallable的对象(表示多线程要执行的任务)
            *       4. 创建FutureTask的对象(作用管理多线程运行的结果)
            *       5. 创建Thread类的对象,并启动(表示线程)
            * */

        //创建MyCallable的对象(表示多线程要执行的任务)
        MyCallable mc = new MyCallable();
        //创建FutureTask的对象(作用管理多线程运行的结果)
        FutureTask<Integer> ft = new FutureTask<>(mc);
        //创建线程的对象
        Thread t1 = new Thread(ft);
        //启动线程
        t1.start();

        //获取多线程运行的结果
        Integer result = ft.get();
        System.out.println(result);


    }
}

三种实现方式对比:

优点缺点
继承Thread类

编程比较简单,可以直接使用

Thread类中的方法

可以扩展性较差,

不能再继承其他的类

实现Runnable接口扩展性强,实现该接口的同时还可以继承其他的类编程相对复杂,不能直接使用Thread类中的方法
实现callable接口

7.设置和获取线程名称线程休眠【应用】

  • 方法介绍

    方法名说明
    void setName(String name)将此线程的名称更改为等于参数name
    String getName()返回此线程的名称
    Thread currentThread()返回对当前正在执行的线程对象的引用
    static void sleep(long millis)使当前正在执行的线程停留(暂停执行)指定的毫秒数

  void setName(String name)           设置线程的名字(构造方法也可以设置名字)
            细节:
                1、如果我们没有给线程设置名字,线程也是有默认的名字的
                        格式:Thread-X(X序号,从0开始的)
                2、如果我们要给线程设置名字,可以用set方法进行设置,也可以构造方法设置

static Thread currentThread()       获取当前线程的对象
            细节:
                当JVM虚拟机启动之后,会自动的启动多条线程
                其中有一条线程就叫做main线程
                他的作用就是去调用main方法,并执行里面的代码
                在以前,我们写的所有的代码,其实都是运行在main线程当中

  static void sleep(long time)        让线程休眠指定的时间,单位为毫秒
            细节:
                1、哪条线程执行到这个方法,那么哪条线程就会在这里停留对应的时间
                2、方法的参数:就表示睡眠的时间,单位毫秒
                    1 秒= 1000毫秒
                3、当时间到了之后,线程会自动的醒来,继续执行下面的其他代码
      

package com.itheima.a04threadmethod1;

public class MyThread extends Thread{

    public MyThread() {
    }

    public MyThread(String name) {
        super(name);
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(getName() + "@" + i);
        }
    }
}




package com.itheima.a04threadmethod1;

public class ThreadDemo {
    public static void main(String[] args) throws InterruptedException {
       /*
            String getName()                    返回此线程的名称
            void setName(String name)           设置线程的名字(构造方法也可以设置名字)
            细节:
                1、如果我们没有给线程设置名字,线程也是有默认的名字的
                        格式:Thread-X(X序号,从0开始的)
                2、如果我们要给线程设置名字,可以用set方法进行设置,也可以构造方法设置

            static Thread currentThread()       获取当前线程的对象
            细节:
                当JVM虚拟机启动之后,会自动的启动多条线程
                其中有一条线程就叫做main线程
                他的作用就是去调用main方法,并执行里面的代码
                在以前,我们写的所有的代码,其实都是运行在main线程当中

            static void sleep(long time)        让线程休眠指定的时间,单位为毫秒
            细节:
                1、哪条线程执行到这个方法,那么哪条线程就会在这里停留对应的时间
                2、方法的参数:就表示睡眠的时间,单位毫秒
                    1 秒= 1000毫秒
                3、当时间到了之后,线程会自动的醒来,继续执行下面的其他代码
       */


        //1.创建线程的对象
        MyThread t1 = new MyThread("飞机");
        MyThread t2 = new MyThread("坦克");



        //2.开启线程
        t1.start();
        t2.start();


        //哪条线程执行到这个方法,此时获取的就是哪条线程的对象
       /* Thread t = Thread.currentThread();
        String name = t.getName();
        System.out.println(name);//main*/

        /*System.out.println("11111111111");
        Thread.sleep(5000);
        System.out.println("22222222222");*/


    }
}

8线程优先级【应用】

  • 线程调度

    • 两种调度方式

      • 分时调度模型:所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间片

      • 抢占式调度模型:优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个,优先级高的线程获取的 CPU 时间片相对多一些

    • Java使用的是抢占式调度模型

    • 随机性

      假如计算机只有一个 CPU,那么 CPU 在某一个时刻只能执行一条指令,线程只有得到CPU时间片,也就是使用权,才可以执行指令。所以说多线程程序的执行是有随机性,因为谁抢到CPU的使用权是不一定的

优先级相关方法

方法名说明
final int getPriority()返回此线程的优先级
final void setPriority(int newPriority)更改此线程的优先级线程默认优先级是5;线程优先级的范围是:1-10
public class MyRunnable implements Runnable{

    @Override
    public void run() {
        for (int i = 1; i <= 100; i++) {
            System.out.println(Thread.currentThread().getName() + "---" + i);
        }
    }
}



public class ThreadDemo {
    public static void main(String[] args){
       /*
            setPriority(int newPriority)        设置线程的优先级
            final int getPriority()             获取线程的优先级
       */

        //创建线程要执行的参数对象
        MyRunnable mr = new MyRunnable();
        //创建线程对象
        Thread t1 = new Thread(mr,"飞机");
        Thread t2 = new Thread(mr,"坦克");

        t1.setPriority(1);
        t2.setPriority(10);

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



    }
}

9.守护线程【应用】

当普通线程执行完之后,那么守护线程也没有继续运行下去的必要了.

  • 相关方法

    方法名说明
    void setDaemon(boolean on)将此线程标记为守护线程,当运行的线程都是守护线程时,Java虚拟机将退出
public class MyThread1 extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(getName() + "---" + i);
        }
    }
}
public class MyThread2 extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(getName() + "---" + i);
        }
    }
}
public class Demo {
    public static void main(String[] args) {
        MyThread1 t1 = new MyThread1();
        MyThread2 t2 = new MyThread2();

        t1.setName("女神");
        t2.setName("备胎");

        //把第二个线程设置为守护线程
        //当普通线程执行完之后,那么守护线程也没有继续运行下去的必要了.
        t2.setDaemon(true);

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

10.礼让线程

     相关方法

方法名说明
public static void yield()出让线程/礼让线程
public class MyThread extends Thread{

    @Override
    public void run() {//"飞机"  "坦克"
        for (int i = 1; i <= 100; i++) {

            System.out.println(getName() + "@" + i);
            //表示出让当前CPU的执行权
            Thread.yield();
        }
    }
}
public class ThreadDemo {
    public static void main(String[] args) {
       /*
            public static void yield()      出让线程/礼让线程

       */

        MyThread t1 = new MyThread();
        MyThread t2 = new MyThread();

        t1.setName("飞机");
        t2.setName("坦克");

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


    }
}

11.插入线程

相关方法

方法名说明
public final void join()

 插入线程/插队线程

public class MyThread extends Thread{

    @Override
    public void run() {
        for (int i = 1; i <= 100; i++) {
            System.out.println(getName() + "@" + i);

        }
    }
}
public class ThreadDemo {
    public static void main(String[] args) throws InterruptedException {
       /*
            public final void join()  插入线程/插队线程
       */



        MyThread t = new MyThread();
        t.setName("土豆");
        t.start();

        //表示把t这个线程,插入到当前线程之前。
        //t:土豆
        //当前线程: main线程
        t.join();

        //执行在main线程当中的
        for (int i = 0; i < 10; i++) {
            System.out.println("main线程" + i);
        }


    }
}

12.线程的生命周期

13.线程的安全问题

  • 安全问题出现的条件

    • 是多线程环境

    • 有共享数据

    • 有多条语句操作共享数据

  • 如何解决多线程安全问题呢?

    • 基本思想:让程序没有安全问题的环境

怎么实现呢?

  • 把多条语句操作共享数据的代码给起来,让任意时刻只能有一个线程执行即可

  • Java提供了同步代码块的方式来解决

同步代码块格式:

synchronized(任意对象) { 
                    多条语句操作共享数据的代码 
}

synchronized(任意对象):就相当于给代码加锁了,任意对象就可以看成是一把锁

特点1:锁默认打卉,有一个线程进去了,锁自动关闭
特点2:里面的代码全部执行完毕,线程出来,锁自动打开

细节:

1.锁必须放在循环里面

2.锁必须唯一,一般都写成当前类的字节码文件 如:synchronized (MyThread.class) {}

同步的好处和弊端

  • 好处:解决了多线程的数据安全问题

  • 弊端:当线程很多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率

14.同步方法解决数据安全问题【应用】

  • 同步方法的格式

    同步方法:就是把synchronized关键字加到方法上

    修饰符 synchronized 返回值类型 方法名(方法参数) { 
        方法体;
    }

    特点1.同步方法是锁住方法里面所有的代码

  • 特点2.锁对象不能自己指定

    同步方法的锁对象是什么呢?

    非静态:this

  • 静态同步方法

    同步静态方法:就是把synchronized关键字加到静态方法上

    修饰符 static synchronized 返回值类型 方法名(方法参数) { 
        方法体;
    }

    同步静态方法的锁对象是什么呢?

    类名.class

15Lock锁【应用】

虽然我们可以理解同步代码块和同步方法的锁对象问题,但是我们并没有直接看到在哪里加上了锁,在哪里释放了锁,为了更清晰的表达如何加锁和释放锁,JDK5以后提供了一个新的锁对象Lock

Lock是接口不能直接实例化,这里采用它的实现类ReentrantLock来实例化

  • ReentrantLock构造方法

    方法名说明
    ReentrantLock()创建一个ReentrantLock的实例
  • 加锁解锁方法

    方法名说明
    void lock()获得锁
    void unlock()释放锁
package com.itheima.a11threadsafe3;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class MyThread extends Thread{

    static int ticket = 0;

    static Lock lock = new ReentrantLock();

    @Override
    public void run() {
        //1.循环
        while(true){
            //2.同步代码块
            //synchronized (MyThread.class){
            lock.lock(); //2 //3
            try {
                //3.判断
                if(ticket == 100){
                    break;
                    //4.判断
                }else{
                    Thread.sleep(10);
                    ticket++;
                    System.out.println(getName() + "在卖第" + ticket + "张票!!!");
                }
                //  }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    }
}

16死锁【理解】

  • 概述

    线程死锁是指由于两个或者多个线程互相持有对方所需要的资源,导致这些线程处于等待状态,无法前往执行

  • 什么情况下会产生死锁

    1. 资源有限

    2. 同步嵌套

17生产者和消费者案例【应用】

Object类的等待和唤醒方法

方法名说明
void wait()导致当前线程等待,直到另一个线程调用该对象的 notify()方法或 notifyAll()方法
void notify()唤醒正在等待对象监视器的单个线程
void notifyAll()唤醒正在等待对象监视器的所有线程
  • 案例需求

    • 桌子类(Desk):定义表示包子数量的变量,定义锁对象变量,定义标记桌子上有无包子的变量

    • 生产者类(Cooker):实现Runnable接口,重写run()方法,设置线程任务

      1.判断是否有包子,决定当前线程是否执行

      2.如果有包子,就进入等待状态,如果没有包子,继续执行,生产包子

      3.生产包子之后,更新桌子上包子状态,唤醒消费者消费包子

    • 消费者类(Foodie):实现Runnable接口,重写run()方法,设置线程任务

      1.判断是否有包子,决定当前线程是否执行

      2.如果没有包子,就进入等待状态,如果有包子,就消费包子

      3.消费包子后,更新桌子上包子状态,唤醒生产者生产包子

    • 测试类(Demo):里面有main方法,main方法中的代码步骤如下

      创建生产者线程和消费者线程对象

      分别开启两个线程

18线程的六种状态

19线程池

线程池的设计思路 :

  1. 准备一个任务容器

  2. 一次性启动多个(2个)消费者线程

  3. 刚开始任务容器是空的,所以线程都在wait

  4. 直到一个外部线程向这个任务容器中扔了一个"任务",就会有一个消费者线程被唤醒

  5. 这个消费者线程取出"任务",并且执行这个任务,执行完毕后,继续等待下一次任务的到来

核心原理:

  1. 创建一个池子,池子中是空的
  2. 提交任务时,池子会创建新的线程对象,任务执行完毕,线程归还给池子,下回再次提交任务时,不需要创建新的线程,直接复用已有的线程即可
  3. 但是如果提交任务时,池子中没有空闲线程,也无法创建新的线程,任务就会排队等待
     

线程池代码实现
1,创建线程池
2,提交任务
3,所有的任务全部执行完毕,关闭线程池


Executors:线程池的工具类通过调用方法返回不同类型的线程池对象。

public static ExecutorService newCachedThreadPool()            创建一个没有上限的线程池 public static newFixedThreadPool(int nThreads)                                创建一个有上限的线程池

public class MyRunnable implements Runnable{
    @Override
    public void run() {
        for (int i = 1; i <= 100; i++) {
            System.out.println(Thread.currentThread().getName() + "---" + i);
        }
    }
}

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class MyThreadPoolDemo {
    public static void main(String[] args) throws InterruptedException {
    /*
        public static ExecutorService newCachedThreadPool()             创建一个没有上限的线程池
        public static ExecutorService newFixedThreadPool (int nThreads) 创建有上限的线程池
    */

        //1.获取线程池对象
        ExecutorService pool1 = Executors.newFixedThreadPool(3);
        //2.提交任务
        pool1.submit(new MyRunnable());
        pool1.submit(new MyRunnable());
        pool1.submit(new MyRunnable());
        pool1.submit(new MyRunnable());
        pool1.submit(new MyRunnable());
        pool1.submit(new MyRunnable());
        //3.销毁线程池
        //pool1.shutdown();
    }
}

自定义线程池

ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor
        (核心线程数量,最大线程数量,空闲线程最大存活时间,任务队列,创建线程工厂,任务的拒绝策略);

        参数一:核心线程数量              不能小于0
        参数二:最大线程数                不能小于0,最大数量 >= 核心线程数量
        参数三:空闲线程最大存活时间       不能小于0
        参数四:时间单位                  用TimeUnit指定
        参数五:任务队列                  不能为null
        参数六:创建线程工厂              不能为null
        参数七:任务的拒绝策略             不能为null

任务拒绝策略

任务拒绝策略说明
ThreadPoolExecutor. AbortPolicy默认策略:丢弃任务并抛出RejectedExecutionException异常
ThreadPoolExecutor.DiscardPolicy丢弃任务,但是不抛出异常这是不推荐的做法
ThreadPoolExecutor.Discardoldestpolicy抛弃队列中等待最久的任务然后把当前任务加入队列中
ThreadPoolExecutor.callerRunsPolicy调用任务的run()方法绕过线程池直接执行
 ThreadPoolExecutor pool = new ThreadPoolExecutor(
                3,  //核心线程数量,能小于0
                6,  //最大线程数,不能小于0,最大数量 >= 核心线程数量
                60,//空闲线程最大存活时间
                TimeUnit.SECONDS,//时间单位
                new ArrayBlockingQueue<>(3),//任务队列
                Executors.defaultThreadFactory(),//创建线程工厂
                new ThreadPoolExecutor.AbortPolicy()//任务的拒绝策略

最大并行数:自己电脑的处理器个数

线程池多大合适?

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

mybiats-puls-插入测试以及雪花算法

一&#xff0c;测试 /* * 插入测试 * */ Test public void test01() {User user new User();/** 自动帮我们生成id* */user.setName("kuku");user.setAge(3);user.setEmail("2983394967qq.com");final int insert mapper.insert(user);System.out.print…

OceanMind海睿思入选《2024 中国MarTech行业生态图》

「Morketing研究院」正式发布《2024 中国MarTech行业生态图》&#xff0c;中新赛克海睿思作为国内数据治理优秀厂商&#xff0c;成功入选「数据与分析」板块「数据管理平台」子类&#xff0c;占据Martech领域关键节点。 ◎《2024中国MarTech行业生态图》 关于MarTech生态图 《…

【Django开发】前后端分离美多商城项目第7篇:登录,使用登录的流程【附代码文档】

美多商城项目4.0文档完整教程&#xff08;附代码资料&#xff09;主要内容讲述&#xff1a;美多商城&#xff0c;项目准备1.B2B--企业对企业,2.C2C--个人对个人,3.B2C--企业对个人,4.C2B--个人对企业,5.O2O--线上到线下,6.F2C--工厂到个人。项目准备&#xff0c;配置1. 修改set…

记录一次Java中使用P12证书访问https,nginx返回403的问题

目录 1、先使用浏览器导入证书访问&#xff0c;测试证书和密钥是否正确2、编写初始java代码3、结果响应 403 Forbidden4、解决方案 1、先使用浏览器导入证书访问&#xff0c;测试证书和密钥是否正确 成功返回&#xff0c;说明p12证书和密钥是没问题的。 2、编写初始java代码 …

智慧公厕是公共厕所信息化向高端发展的必然

现代社会的发展离不开科技的加持&#xff0c;公共厕所作为城市基础设施之一&#xff0c;也在不断引入智慧化的概念&#xff0c;实现信息化、智慧化和数字化的使用和管理。智慧公厕通过物联网、大数据、云计算、网络通信和自动化控制技术的应用&#xff0c;成为了高级的社会公共…

【vue】watchEffect 自动侦听器

watchEffect&#xff1a;自动监听值的变化 获取旧值时&#xff0c;不是很方便&#xff0c;建议用watch <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevic…

哪些被Asterisk 21版本暴砍的功能有多少是你常用的?我指的是chan_alsa

目录 江湖再无NoCDRapp_macro也不见了常用的还有哪些&#xff1f; Asterisk 21.0版本的发布&#xff0c;主打一个剪刀手。 正如社区官方傲慢、粗鲁&毫不遮掩的说法&#xff1a; Asterisk 21 saw fewer new additions than previous versions. Many of the changes are actu…

element table 使用了表格固定height高度和表格属性fixed属性出现了高度错乱bug

问题描述&#xff1a;因为使用了表格固定height高度所以 使用表格属性fixed属性出现了高度错乱bug知识点&#xff1a;使用element table 里提供的doLayout 方法 代码 // template <el-table ref"test" ></el-table>//js// 查询数据getList(obj{}) {get…

电焰灶十大品牌:华火电燃灶怎么样?

随着科技的发展和人们生活品质的提升&#xff0c;传统燃气灶具已无法满足现代家庭对于高效、环保、安全的需求。在这一背景下&#xff0c;电焰灶作为一种新型的厨房设备逐渐崭露头角。在众多电焰灶品牌中&#xff0c;华火电燃灶凭借其卓越的性能和创新的技术&#xff0c;成功跻…

【MATLAB第104期】基于MATLAB的xgboost的敏感性分析/特征值排序计算(针对多输入单输出回归预测模型)

【MATLAB第104期】基于MATLAB的xgboost的敏感性分析/特征值排序计算&#xff08;针对多输入单输出回归预测模型&#xff09; 因matlab的xgboost训练模型不含敏感性分析算法&#xff0c;本文通过使用single算法&#xff0c;即单特征因素对输出影响进行分析&#xff0c;得出不同…

NAPI 类对象导出及其生命周期管理(下)

4. 样例工程源码剖析 工程的模板是Native C,模型是Stage。源码剖析主要围绕以下几个文件 4.1. NAPI导出对象和生命周期管理具体实现 4.1.1. 定义NapiTest类及方法 Napi.h文件内容如下&#xff1a; #ifndef __NAPI_TEST_H__ #define __NAPI_TEST_H__#include "napi/nat…

集群监控原理

3.1.2.集群监控原理 Sentinel基于心跳机制监测服务状态&#xff0c;每隔1秒向集群的每个实例发送ping命令&#xff1a; •主观下线&#xff1a;如果某sentinel节点发现某实例未在规定时间响应&#xff0c;则认为该实例主观下线。 •客观下线&#xff1a;若超过指定数量&…

华为远程登陆管理配置:轻松掌握核心要点

实验拓扑及需求 实验步骤 A、配置相关地址及连通性测试 R1&#xff1a; [R1]int GigabitEthernet 0/0/0 [R1-GigabitEthernet0/0/0]ip address 192.168.12.1 24 R2&#xff1a; [R2]int gi 0/0/0 [R2-GigabitEthernet0/0/0]ip add 192.168.12.2 24 [R2]int gi 0/0/1 […

使用 Docker 部署 Linux-Command 命令搜索工具

1&#xff09;介绍 Linux-Command GitHub&#xff1a;https://github.com/jaywcjlove/linux-command Linux-Command 仓库搜集了 580 多个 Linux 命令&#xff0c;是一个非盈利性的仓库&#xff0c;生成了一个 Web 网站方便使用&#xff0c;目前网站没有任何广告&#xff0c;内…

阿里云4核16G服务器可以用来做什么?

阿里云4核16G服务器可以用来做什么&#xff1f;可用来搭建游戏服务器&#xff0c;阿里云4核16G服务器10M带宽30元1个月、90元3个月&#xff0c;优惠活动 aliyunfuwuqi.com/go/youhui 阿里云4核16G服务器可以用来做什么&#xff1f;除了搭建游戏服务器&#xff0c;还可以用来哪…

阿里云短信服务对接流程

阿里云短信服务是阿里巴巴集团推出的一款通讯服务产品&#xff0c;支持发送短信到手机、验证码短信、语音短信等多种短信场景。通过阿里云短信服务&#xff0c;企业可以方便、快捷、安全地将消息发送给用户&#xff0c;提升用户体验和品牌形象。此外&#xff0c;阿里云短信服务…

各种拟合算法整理

各种拟合算法整理 1. 最小二乘法2. 霍夫变换3. RANSAC算法 本篇将介绍最小二乘法(Least Square)、霍夫变换(Hough Transform)和RANSAC(random sample consensus&#xff0c;随机抽样一致性算法)算法的原理、应用和代码。 如果已经知道了一组可靠的点&#xff0c;可以直接使用最…

QAT量化 demo

一、QAT量化基本流程 QAT过程可以分解为以下步骤&#xff1a; 定义模型&#xff1a;定义一个浮点模型&#xff0c;就像常规模型一样。定义量化模型&#xff1a;定义一个与原始模型结构相同但增加了量化操作&#xff08;如torch.quantization.QuantStub()&#xff09;和反量化…

【Canvas技法】四条C形色带填满一个圆/环形

【关键点】 通过三角函数计算控制点的位置。 【成果图】 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <head><title>四条C形色带填满一个…

【复现】浙大恩特客户资源管理系统 SQL注入漏洞_71

目录 一.概述 二 .漏洞影响 三.漏洞复现 1. 漏洞一&#xff1a; 四.修复建议&#xff1a; 五. 搜索语法&#xff1a; 六.免责声明 一.概述 浙大恩特客户资源管理系统是一款针对企业客户资源管理的软件产品。该系统旨在帮助企业高效地管理和利用客户资源&#xff0c;提升…