day24_多线程进阶

news2025/1/8 5:08:10

今日内容

上课同步视频:CuteN饕餮的个人空间_哔哩哔哩_bilibili
同步笔记沐沐霸的博客_CSDN博客-Java2301
零、 复习昨日
一、作业
二、线程安全的集合
三、死锁
四、线程通信
五、生产者消费者
六、线程池

零、 复习昨日

创建线程的几种方式 1) 继承 2) 实现Runnable 3) callable接口 Future接口 4) 线程池
启动线程的方法 start()
线程的几种状态
什么是线程不安全


setName getName
Thread.currentThread()
join
sleep


synchronized

一、作业

售卖后车票

package com.qf.homework;

/**
 * --- 天道酬勤 ---
 *
 * @author QiuShiju
 * @desc
 */
public class Window implements Runnable {

    // 票(加static,被该类所有对象共享)
    private static int ticket = 100;

    // 售票任务
    @Override
    public void run() {
        while (true) {
            synchronized (Window.class) {
                if (ticket > 0) {
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace( );
                    }
                    System.out.println(Thread.currentThread( ).getName( ) + "有余票,正在售出" + ticket);
                    ticket--;
                } else {
                    System.out.println("票已售完");
                    return;
                }
            }
        }
    }
}
    public static void main(String[] args) {
        new Thread( new Window() ,"窗口1").start();
        new Thread( new Window() ,"窗口2").start();
        new Thread( new Window() ,"窗口3").start();
    }

二、线程安全的集合[了解]

StringBuffer是线程安全的,是因为每个方法都加上synchronized,即都是同步方法
StringBuilder没有加

image-20230303094122011

image-20230303094159112

ArrayList是线程不安全
Vector 是线程安全

image-20230303094527278

HashMap 是线程不安全
Hashtable 是线程安全

image-20230303095012216

比HashMap安全,比Hashtable快,即安全又快的集合ConcurrentHashMap[很重要]

三、死锁[了解]

死锁: 互相持有对方的锁还不释放

public class MyLock {
    static Object zuo = new Object();
    static Object you = new Object();
}
public class Boy extends Thread{

    @Override
    public void run() {
        synchronized (MyLock.zuo){
            System.out.println("男朋友-拿到左筷子" );
            synchronized (MyLock.you) {
                System.out.println("男朋友-拿到右筷子,开吃" );
            }
        }
    }
}
public class Girl extends Thread{

    @Override
    public void run() {
        synchronized (MyLock.you){
            System.out.println("女朋友-拿到右筷子" );
            synchronized (MyLock.zuo) {
                System.out.println("女朋友-拿到左筷子,开吃" );
            }
        }
    }
}
public class TestDeadLock {
    public static void main(String[] args) {
        new Boy().start();
        new Girl().start();

    }
}

男生先拿到zuo锁,再去获得you锁即可吃饭
但是you锁在女生那里,女生需要获得zuo锁才能吃饭
即 男生需要的you锁被女生拿着,女生需要的zuo锁被男生拿着
互相持有对方的锁,还不释放,就会出现"死锁" 程序卡死,不往下执行,持续阻塞

四、线程通信[熟悉]

4.1 介绍

线程通信,就是线程之间产生联系.

即通知,例如线程A执行到一定时候会停下,同时通知另外的线程B执行,
线程B执行到一定时候,也停下,通知线程A执行

以上操作需要Object类的方法

  • wait() 让当前线程等待
  • notify() 唤醒一个处于等待状态的线程
  • notifyAll() 唤醒所有处于等待状态的线程

4.2 两个个线程通信

需求: 昨天打印机方法,让print1()和print2()方法交替执行

package com.qf.notify;

/**
 * --- 天道酬勤 ---
 *
 * @author QiuShiju
 * @desc 打印机类
 */
public class Printer {

    // 具体哪台打印机执行的标志
    private int flag = 1;

    // 现在使用同步方法,print1和print2方法由同一个对象打印机对象调用
    // print1方法和print2方法锁是同一个,是this,即打印机对象
    public synchronized void print1() {
        if (flag != 1) {
            try {
                // 锁是谁,就用谁调用wait
                // 当前线程就陷入等待,会让出资源释放锁
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace( );
            }
        }
        System.out.print("1 ");
        System.out.print("2 ");
        System.out.print("3 ");
        System.out.print("4 ");
        System.out.print("\r\n");

        // 干完活,修改标志
        flag = 2;

        // 通知另外一个处于等待状态的线程
        // 锁是谁,用谁调用方法
        this.notify();
    }


    public synchronized void print2() {
        if (flag != 2) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace( );
            }
        }
        System.out.print("A ");
        System.out.print("B ");
        System.out.print("C ");
        System.out.print("D ");
        System.out.print("\r\n");

        flag = 1;
        this.notify();
    }
}
// 测试
public class TestNotify {

    public static void main(String[] args) {

        Printer printer = new Printer( );

        new Thread(){
            @Override
            public void run() {
                while (true){
                    printer.print1();
                }
            }
        }.start();

        new Thread(){
            @Override
            public void run() {
                while (true){
                    printer.print2();
                }
            }
        }.start();
    }
}

换用同步代码块实现

package com.qf.notify;

/**
 * --- 天道酬勤 ---
 *
 * @author QiuShiju
 * @desc 打印机类
 */
public class Printer {

    // 锁对象
    private Object obj = new Object();

    // 具体哪台打印机执行的标志
    private int flag = 1;

    // 现在使用同步方法,print1和print2方法由同一个对象打印机对象调用
    // print1方法和print2方法锁是同一个,是this,即打印机对象
    public void print1() {
        // 同步代码块,现在锁是字节码文件
        synchronized(Printer.class) {
            if (flag != 1) {
                try {
                    // 锁是谁,就用谁调用wait
                    // 当前线程就陷入等待,会让出资源释放锁
                    // 用字节码锁来调用wait方法
                    Printer.class.wait( );
                } catch (InterruptedException e) {
                    e.printStackTrace( );
                }
            }
            System.out.print("1 ");
            System.out.print("2 ");
            System.out.print("3 ");
            System.out.print("4 ");
            System.out.print("\r\n");

            // 干完活,修改标志
            flag = 2;

            // 通知另外一个处于等待状态的线程
            // 只能唤醒在此对象监视器(加过锁的)上等待的单个线程.
            // 如果没有加锁,直接调用该方法唤醒线程,会报错IllegalMonitorStateException
            // 锁是谁,用谁调用方法
            Printer.class.notify( );

        }
    }


    public  void print2() {
        synchronized( Printer.class) {
            if (flag != 2) {
                try {
                    Printer.class.wait( );
                } catch (InterruptedException e) {
                    e.printStackTrace( );
                }
            }
            System.out.print("A ");
            System.out.print("B ");
            System.out.print("C ");
            System.out.print("D ");
            System.out.print("\r\n");

            flag = 1;
            Printer.class.notify( );
        }
    }
}

4.3 练习

创建A1 A2 两个线程,分别打印1-10,11-20,保证A1执行完再 执行A2线程,A2执行完再执行A1

A1 —> 1
A2 —>11
A1 —> 2
A1 —>12

package com.qf.notify;

/**
 * --- 天道酬勤 ---
 *
 * @author QiuShiju
 * @desc
 */
public class A1 extends Thread{
    @Override
    public void run() {
        synchronized (TestA1A2.class) {
            for (int i = 1; i < 11; i++) {
                if (TestA1A2.flag != 1) {
                    try {
                        TestA1A2.class.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace( );
                    }
                }
                System.out.println("A1 --> " + i);
                TestA1A2.flag  = 2;
                TestA1A2.class.notify();
            }
        }
    }
}
class A2 extends Thread{
    @Override
    public void run() {
        synchronized (TestA1A2.class) {
            for (int i = 11; i < 21; i++) {
                if (TestA1A2.flag != 2) {
                    try {
                        TestA1A2.class.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace( );
                    }
                }
                System.out.println("A2 --> " + i);

                TestA1A2.flag  = 1;
                TestA1A2.class.notify();
            }
        }
    }
}
class TestA1A2{
    static int flag = 1;
    public static void main(String[] args) {
        new  A1().start();
        new  A2().start();

    }
}

4.4 三个线程的通信

第一次
线程3抢到,判断标志是1,不是自己执行,改动标志为2,随机唤醒一条线程,但是此时所有线程都处于就绪状态,唤醒不唤醒无所谓…


第二次
假如线程2抢到,判断标志是2,自己执行,改动标志为3,随机唤醒一条线程,但是此时所有线程都处于就绪状态,唤醒不唤醒无所谓…


第三次
假如线程3抢到,判断标志是3,自己执行,改动标志为1,随机唤醒一条线程,但是此时所有线程都处于就绪状态,唤醒不唤醒无所谓…


第四次
假如这次又是线程3抢到,判断标志是1,不是自己执行,线程3陷入等待状态,让出资源
如果此时线程2抢到,判断标志是1,不是自己执行,线程2陷入等待状态,让出资源
此时只能线程1执行,判断标志是1,自己执行,改动标志为2,随机唤醒一条线程,如果唤醒是线程3,线程3从等待状态起来后通过while继续判断标志,发现不是自己,继续等待.此时只有线程1活跃,那么线程1执行,判断标志发现不是自己,陷入等待

解决方案: 全部唤醒 ,使用方法notifyAll(),唤醒所有处于等待状态的线程

package com.qf.notify;

/**
 * --- 天道酬勤 ---
 *
 * @author QiuShiju
 * @desc 打印机类
 */
public class Printer2 {

    private int flag = 1;

    public void print1() {
        synchronized(Printer2.class) {
            // 改成while,让线程被唤醒后,继续判断
            // 如果是自己就执行,不是自己的标志就继续休眠
            while (flag != 1) {
                try {
                    // 哪里等待,哪里起来继续执行
                    Printer2.class.wait( );
                } catch (InterruptedException e) {
                    e.printStackTrace( );
                }
            }
            System.out.print("1 ");
            System.out.print("2 ");
            System.out.print("3 ");
            System.out.print("4 ");
            System.out.print("\r\n");

            flag = 2;
            // 唤醒的是一条处于等待状态的线程(随机唤醒一条)
            // Printer2.class.notify( );
            // 唤醒所有等待的线程
            Printer2.class.notifyAll( );

        }
    }

    public  void print2() {
        synchronized( Printer2.class) {
            while (flag != 2) {
                try {
                    Printer2.class.wait( );
                } catch (InterruptedException e) {
                    e.printStackTrace( );
                }
            }
            System.out.print("A ");
            System.out.print("B ");
            System.out.print("C ");
            System.out.print("D ");
            System.out.print("\r\n");

            flag = 3;
            Printer2.class.notifyAll( );
        }
    }

    public  void print3() {
        synchronized( Printer2.class) {
            while (flag != 3) {
                try {
                    Printer2.class.wait( );
                } catch (InterruptedException e) {
                    e.printStackTrace( );
                }
            }
            System.out.print("一 ");
            System.out.print("二 ");
            System.out.print("三 ");
            System.out.print("四 ");
            System.out.print("\r\n");

            flag = 1;
            Printer2.class.notifyAll( );
        }
    }
}

第一次
线程3抢到,判断标志是1,不是自己执行,线程3陷入等待状态,让出资源


第二次
线程2抢到,判断标志是1,不是自己执行,线程2陷入等待状态,让出资源


第三次
线程1抢到,判断标志是1,自己执行,改动标志为2,随机唤醒一条线程
假如唤醒的是线程2,判断标志是2,自己执行,改动标志为3,唤醒线程3
但是假设线程2抢到,判断标志不是自己,线程2等待
假设线程1抢到,判断标志为3,不是自己,线程1也等待
线程3抢到资源开始执行,改动标志为1
随机唤醒一条线程,假如唤醒的线程2,现在判断标志是1,不是自己执行
线程2继续等待,现在活着的是线程3,抢到资源,判断标志不是自己,继续等待

4.5 总结

特殊的:

  • wait和notify方法需要在同步方法或者同步代码块内执行
  • wait会让当前线程进入等待状态,让出资源,其他线程可以执行
  • wait和notify()方法谁调用? 当前锁对象是谁,就是谁调用该方法

问 wait和sleep有什么区别?

答:

  • wait是Object类的方法,sleep是Thread类方法

  • wait和sleep都可以让当前线程进入阻塞状态

  • 但是wait阻塞当前线程,会让出系统资源,其他线程可执行;但是sleep阻塞当前线程,会持有锁不释放,其他线程无法执行

  • wait需要在同步方法或同步代码快中使用,但是sleep可以在同步或非同步都可以使用


问 为什么wait和notify方法要设计在Object类中?

答: 因为锁可以是任意对象,又因为wait和notify需要被 锁对象调用,那么锁对象是任意的,wait和notify方法也能被任意对象调用,所以就设计在Object类中,因为Object类是所有类的父类

五、生产者消费者

若干个生产者在生产产品,这些产品将提供给若干个消费者去消费,为了使生产者和消费者能并发执行,在两者之间设置⼀个能存储多个产品的缓冲区,生产者将生产的产品放入缓冲区中,消费者从缓 冲区中取走产品进行消费,显然生产者和消费者之间必须保持同步,即不允许消费者到⼀个空的缓冲区中取产品,也不允许生产者向⼀个满的缓冲区中放入产品。

商品类 Phone
商店类 Shop

package com.qf.pc;

/**
 * --- 天道酬勤 ---
 *
 * @author QiuShiju
 * @desc
 */
public class Phone {
    String name;

    public Phone(){}
    public Phone(String name){
        this.name = name;
    }
}
class Shop {

    Phone phone;

    // 进货(生产)
    public synchronized void putPhone(Phone phone) {
        if (this.phone != null) {
            // 有货,先等待,让别人消费
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace( );
            }
        }

        // 进货
        this.phone = phone;
        System.out.println("进货,"+phone.name );
        // 通知消费
        this.notify();
    }

    // 售货(消费)
    public synchronized void sellPhone() {
        if (this.phone == null) {
            // 没有商品,不能消费,先等待生产
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace( );
            }
        }
        // 消费
        System.out.println("消费,"+phone.name );
        this.phone = null;
        // 通知生产
        this.notify();
    }
}
class TestPC {

    public static void main(String[] args) {
        Shop shop = new Shop( );
        // 生产者线程
        new Thread(){
            @Override
            public void run() {
                for (int i = 1; i < 6; i++) {
                    shop.putPhone(new Phone("IPhone"+i));
                }
            }
        }.start();

        // 消费者线程
        new Thread(){
            @Override
            public void run() {
                for (int i = 1; i < 11; i++) {
                    shop.sellPhone();
                }
            }
        }.start();
    }
}

六、线程池

6.1 线程池概念

  • 如果有非常多的任务需要非常多的线程来完成,每个线程的工作时间不长,就需要创建很多线程,工作完又立即销毁[线程频繁创建和销毁线程]
  • 频繁创建和销毁线程非常消费性能,那么线程池,就是可以创建一些线程,放在"池子"中,用的时候去池子取一个线程去使用,使用完再放回去,线程可以重用
  • 线程池,底层其实就是集合队列,里面存储线程对象,用的时候去抽即可,就不要频繁创建线程了

使用线程池的好处是减少在创建和销毁线程上所花的时间以及系统资源的开销,解决资
源不足的问题。如果不使用线程池,有可能造成系统创建大量同类线程而导致消耗完内存或者
“过度切换”的问题 --> 摘自阿里官方手册

6.2 线程池原理

image-20230301230326324

将任务(task)提交(submit/execute)给线程池(threadpool),由线程池分配线程,运行任务,任务结束后,线程重新放入线程池供后续线程使用

6.3 创建线程池的方式

使用线程池创建线程,执行任务

JDK提供了关于线程池的一些类和接口

  • Executor: 线程池的根接口,通过execute(Runnable task) 执行任务
  • ExecutorService: Executor的子接口,通过submit(Runnable task) 来提交任务,执行任务
  • ThreadPoolExecutor: ExecutorService的子实现类,通过submit(Runnable task) 来提交任务,执行任务
  • Executors: 执行器类(线程池工厂类),通过该类来获得不同特点的线程池对象
    类中有很多静态方法,直接调用就可以获得各种特点线程池对象

6.4 不同特点的线程池

通过Executors调用以下静态方法获得不同特点的线程池对象

方法类型解释
newFixedThreadPool固定大小线程池池中包含固定数目的线程,空闲线程一直保留。只有核心线程,线程数量固定,任务队列为LinkedBlockingQueue
newCachedThreadPool动态大小的线程池,原则上无上限无核心线程,非核心线程数量无限,执行完闲置60s后回收,任务队列SynchronousQueue
newScheduledThreadPool可以执行定时任务的线程池用于调度执行的固定线程池,执行定时或周期性任务。和弦线程数量固定,非核心线程数量无线,执行完闲置10ms后回收,任务队列为DelayedWorkQueue
newSingleThreadExecutor单线程线程池只有一个线程的池,会顺序执行提交的任务,只有一个核心线程,无非核心线程,任务队列为LinkdBlockingQueue
newSingleThreadScheduledExecutor单线程定时任务线程池
newWorkStealingPool1.8提供新的方式创建线程池

以上线程池操作在阿里java开发手册中是不建议用的…

说明:Executors 返回的线程池对象的弊端如下:
1)FixedThreadPool 和 SingleThreadPool:
允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。
2)CachedThreadPool 和 ScheduledThreadPool:
允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。
-----------------------
OOM 内存溢出,即系统资源耗尽

线程池执行任务时,可以采用两种方法:

execute(): 没有返回值,无法判断任务是否执行成功

submit():会返回Future对象,通过该对象判断任务是否执行成功

    public static void main(String[] args) {

        // 固定大小线程池
        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);

        for (int i = 0; i < 50; i++) {
            fixedThreadPool.execute(new Runnable( ) {
                @Override
                public void run() {
                    // System.out.println(Thread.currentThread().getName()+"干活" );
                }
            });
        }
        // 动态调整大小线程池
        ExecutorService fixedThreadPool2 = Executors.newCachedThreadPool();
        for (int i = 0; i < 50; i++) {
            fixedThreadPool2.execute(new Runnable( ) {
                @Override
                public void run() {
                   // System.out.println(Thread.currentThread().getName()+"干活" );
                }
            });
        }

        // 定时线程池
        ScheduledExecutorService  scheduledExecutor = Executors.newScheduledThreadPool(3);
        for (int i = 0; i < 5; i++) {
            scheduledExecutor.schedule(new Runnable( ) {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName()+"干活" );
                }
            },3, TimeUnit.SECONDS);
        }
    }

6.5 ThreadPoolExecutor[重要]

  • ThreadPoolExecutor 很重要,有7个参数
参数名解释备注
int corePoolSize指定线程池的线程数量(核心线程数)不能小于0
int maximumPoolSize指定线程池可支持的最大线程数最大数量>=核心线程数
long keepAliveTime指定临时线程的最大存活时间不能小于0
TimeUnit unit指定存活时间的单位(秒,分,时,天)时间单位
BlockingQueue workQueue指定任务队列
ThreadFactory threadFactory指定哪个线程工厂创建线程
RejectedExecutionHandler handler指定线程忙,任务队列满的时候新任务来了怎么办?拒绝策略

问: 什么是创建临时线程?
答: 新任务提交时发现核心线程都在忙,任务队列也满了,并且还可以创建临时线程,此时才会创建线程

问:什么时候开始拒绝任务?
答:核心线程和临时线程都在忙,任务队列也满了,新的任务过来就会拒绝

LinkedBlockingQueue<Runnable> queue = new LinkedBlockingQueue<>(10);
ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(5, 15, 10, TimeUnit.SECONDS, queue);

for (int i = 0; i < 50; i++) {
    poolExecutor.submit(new Runnable( ) {
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName()+"干活" );
        }
    });
}

今天这些都是会说,理解,能讲出来,不在于敲代码

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

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

相关文章

【jeecg】vue-cli-service不是内部或外部命令,也不是可运行的程序

npm run serve时&#xff0c;报错 vue-cli-service不是内部或外部命令,也不是可运行的程序 参考该链接 &#xff0c;找到生成的log文件&#xff0c; 在log文件里看到了C盘的地址 找到这个地址&#xff0c;发现里面有 我之前下载的yarn &#xff08;原来下在了这里&#xff09;没…

微服务一 实用篇 - 4.1 RabbitMQ部署

《微服务一 实用篇 - 4.1 RabbitMQ部署》 提示: 本材料只做个人学习参考,不作为系统的学习流程,请注意识别!!! 《微服务一 实用篇 - 4.1 RabbitMQ部署》《微服务一 实用篇 - 4.1 RabbitMQ部署》RabbitMQ部署指南1.单机部署1.1.下载镜像1.2.安装MQ2.集群部署2.1.集群分类2.2.设…

B - Build Roads (最小生成树 + 打表)

https://vjudge.net/problem/Gym-103118B/origin 在猫的国度里&#xff0c;有n个城市。猫国国王想要修n -1条路来连接所有的城市。第i市有一家ai经验价值的建筑公司。要在第i市和第j市之间修建公路&#xff0c;两个城市的建筑公司需要相互合作。但是&#xff0c;在修路的过程中…

Windows安装VMware+创建Linux虚拟机

目录1&#xff1a;简介2&#xff1a;功能特点3&#xff1a;VM下载地址4&#xff1a;安装VMware5&#xff1a;下载iso虚拟机镜像6&#xff1a;创建Linux虚拟机7&#xff1a;配置静态ip1&#xff1a;简介 VMware Workstation Pro&#xff08;曾用名VMware Workstation&#xff09…

供应商绩效管理指南:挑战、考核指标与管理工具

管理和优化供应商绩效既关键又具有挑战性。要知道价格并不是一切&#xff0c;如果你的供应商在商定的价格范围内向你开具发票&#xff0c;但服务达不到标准或货物不合格&#xff0c;你也无法达到节约成本的目标。 供应商绩效管理可以深入了解供应商可能带来的风险&#xff0c…

SpringCloud之认识微服务

文章目录一、传统项目转型二、走进 SpringCloud三、微服务项目搭建3.1 创建一个 SpringBoot 项目3.2 创建三个 Maven 子工程3.3 为子工程创建 application.yml3.4 引入依赖3.5 数据库 建库建表3.6 编写业务提示&#xff1a;以下是本篇文章正文内容&#xff0c;SpringCloud系列学…

Vim笔记

文章目录VIM四种模式命令模式编辑模式末行模式可视化模式扩展内容VIM四种模式 1、命令模式 2、编辑模式 3、末行模式 4、可视化模式 5、VIM四种模式的关系 命令模式 1、命令模式下我们能做什么&#xff1a;① 移动光标 ② 复制 粘贴 ③ 剪切 粘贴 删除 ④ 撤销与恢复 2、进…

【分布式】分布式唯一 ID 的 8 种生成方案

文章目录前言正文什么是分布式ID&#xff1f;分布式ID的特性&#xff1f;分布式ID的生成方案1. UUID2. 数据库自增ID3. 批量生成ID4. Redis生成ID5. Twitter的snowflake算法6. 百度UidGenerator7. 美团Leaf8.滴滴&#xff08;Tinyid&#xff09;小结前言 在互联网的业务系统中…

Leaflet基础入门教程(一)

leaflet是一个前端的轻量的gis框架,为什么说它轻量呢。因为相比于传统的“庞大的”GIS框架比如openlayers和mapbox,leaflet不仅代码体积小,而且API构成也极为简单。是GIS行业小白入门级别学习的最好的框架,没有之一。 那么话不多说我们首先来学习一下如何使用leaflet搭建一…

Vue3中hook的使用及使用中遇到的坑

目录前言一&#xff0c;什么是hook二&#xff0c; hook函数的使用2.1 铺垫2.2 hook函数的写法2.3 使用写好的hook函数后记前言 在学习Es6的时候&#xff0c;我们开始使用类与对象&#xff0c;开始模块化管理&#xff1b;在Vue中我们可以使用mixin进行模块化管理&#xff1b;Vu…

2023-03-03干活小计

今天见识了 归一化的重要性&#xff1a;归一化 不容易爆炸 深度了解了学习率&#xff1a;其实很多操作 最后的结果都是改变了lr 以房价预测为例&#xff1a;一个点一个点更新 比较 矩阵的更新&#xff1a; 为什么小批量梯度下降 优于随机梯度下降 优于批量梯度下降&#xff…

Kubernetes 中 Deployment 使用

Deployment的使用 之前我们了解了Replication Controller和Replica Set两种资源对象&#xff0c;RC和RS的功能基本上是差不多的&#xff0c;唯一的区别就是RS支持集合的selector。也了解到了用RC/RS来控制Pod副本的数量&#xff0c;也实现了滚动升级Pod的功能。现在看上去似乎…

【面试题】前端路由分类

0. 前言 在Web开发中&#xff0c;路由是指根据用户请求的URL地址&#xff0c;确定用户访问的页面资源、参数等&#xff0c;是前端开发中不可缺少的重要部分。Vue router中提供了两种路由模式&#xff0c;一种是hash模式&#xff0c;另一种是history模式。 1. Hash模式路由 H…

爆款升级!新系列南卡Neo最强旗舰杀到,业内首款无线充骨传导耳机!

中国专业骨传导耳机品牌NANK南卡于近日发布了全新南卡Neo骨传导运动耳机&#xff0c;打造一款佩戴最舒适、音质体验最好的骨传导耳机。推出第2代声学響科技技术&#xff0c;提供更优质的开放式骨传导听音体验&#xff0c;透过不一样的音质体验&#xff0c;打造更好的骨传导耳机…

MySQL基础(二)排序与分页、多表查询、单行函数

上接 MySQL基础&#xff08;一&#xff09;SQL分类、导入、SELECT语句&#xff0c;运算符_独憩的博客-CSDN博客 目录 排序与分页 排序 二级排序 分页 多表查询 基础多表查询 等值连接vs非等值连接 自连接vs非自连接 内连接vs外连接 自然连接 单行函数 数值函数 …

信息系统基本知识(四)新技术

大纲 信息系统与信息化信息系统开发方法常规信息系统集成技术软件工程新一代信息技术信息系统安全技术信息化发展与应用信息系统服务管理信息系统服务规划企业首席信息管及其责任 1.5 新一代技术 1.5.1 物联网 概念&#xff1a;&#xff08;The Internet of Things&#xf…

你只会说MVC模型是什么但是不会实现?今天带你走通Web、Servlet、MVC、SpringMVC。代码演示很清晰

文章目录HTTP请求和HTTP响应从0手写一个Web服务器&#xff0c;看看能有多累人使用Servlet实现一个服务器&#xff0c;看看多简单Serlvet的创建Servlet的运行Servlet的其他问题Servlet这么爽&#xff0c;我们简单地探索一下它的原理JSP跟Servlet合作啦&#xff0c;我们来看一下他…

学习ROS时针对gazebo相关的问题(重装与卸载是永远的神)

ResourceNotFound:gazebo_ros 错误解决 参考:https://blog.csdn.net/weixin_42591529/article/details/123869969 当将机器人加载到gazebo时,运行launch文件出现如下错误 这是由于缺少gazebo包所导致的。 解决办法:

Linux 学习 挂载、卸载光盘和实现虚拟机时间同步

/media&#xff1a;挂载光盘使用的 挂载光盘命令&#xff1a;mount /dev/cdrom /media 卸载光盘命令&#xff1a;umount /dev/cdrom 挂载光盘 使用挂在光盘命令挂载光盘&#xff0c;如图所示 卸载光盘 初次卸载光盘可能会出现问题 [rootlocalhost media]# umount /dev/cd…

linux定时任务打包提权docker组提权

定时任务有打包命令&#xff0c;这个命令有参数调用可以执行其他命令&#xff0c;定时任务因为是root用户执行的&#xff0c;所以就会造成提权。一、linux定时任务打包提权复现环境&#xff1a;ubuntun14.041.创建定时任务&#xff1a;在最下面写入&#xff1a;* * * * * …