当前位置: 首页 > news >正文

JavaEE-经典多线程样例

文章目录

  • 单例模式
    • 设计模式初步引入
    • 为何存在单例模式
    • 饿汉式单例模式
    • 饿汉式缺陷以及是否线程安全
    • 懒汉式单例模式
    • 基础懒汉式缺陷以及是否线程安全
    • 懒汉式单例模式的改进
    • 完整代码(变量volatile)
  • 阻塞队列
    • 生产者消费者模型
    • 生产者消费者模型的案例以及优点
      • 请求与响应案例
      • 解耦合
      • 削峰填谷
    • 阻塞队列的内置API
    • 阻塞队列的模拟实现
      • 关于wait和while的搭配使用
      • 模拟实现

单例模式

设计模式初步引入

啥是设计模式?

  • 设计模式好⽐象棋中的 “棋谱”. 红⽅当头炮, ⿊⽅⻢来跳. 针对红⽅的⼀些⾛法, ⿊⽅应招的时候有⼀些固定的套路. 按照套路来⾛局势就不会吃亏.软件开发中也有很多常⻅的 “问题场景”. 针对这些问题场景, ⼤佬们总结出了⼀些固定的套路. 按照这个套路来实现代码, 也不会吃亏, 不针对某一种语言, 而是针对某种开发场景
  • 设计模式并不是只有23种, 因为之前有些大佬写了一本书叫设计模式,重点讨论了23种, 但事实上存在更多种的设计模式
  • 设计模式与框架的区别就是, 设计模式在开发中是软性要求(不一定遵守), 但是框架是硬性要求(一定要遵守)

简单点一句话总结

设计模式是前人根据一些开发场景给出的一些经验之谈, 所以设计模式并不针对某一种语言

为何存在单例模式

  • 单例模式能保证某个类在程序中只存在唯⼀⼀份实例, ⽽不会创建出多个实例.
    这⼀点在很多场景上都需要. 比如 JDBC 中的 DataSource 实例就只需要⼀个,再
    比如如果一个类的创建需要加载的数据量非常的庞大(GB级别), 那我们不希望这
    个类频繁的创建销毁(开销很大), 我们可能只是希望创建一次就可以了

饿汉式单例模式

顾名思义, 这种方式实现的单例模式十分"饥渴", 不管使用不使用都会提前new一个对象

流程如下

  • 构造方法私有化
  • 定义一个静态的类对象用以返回
  • 提供一个公开的静态接口来获取唯一的对象

测试代码如下

/*** 下面定义一个类来测试饿汉式单例模式*/
class HungrySingleton{// 提供一个静态的变量用来返回private static HungrySingleton hungrySingleton = new HungrySingleton();// 构造方法私有化(在外部不可以构造对象)private HungrySingleton(){}// 提供一个获取实例的静态公开接口public static HungrySingleton getInstance(){return hungrySingleton;}
}public class DesignPatternTest {public static void main(String[] args) {// 对饿汉式单例的测试HungrySingleton instance1 = HungrySingleton.getInstance();HungrySingleton instance2 = HungrySingleton.getInstance();// 测试两者是不是一个对象System.out.println(instance1 == instance2);}
}

测试结果
在这里插入图片描述
很明显, 用这种方式创建的实例都是只有一份的…

饿汉式缺陷以及是否线程安全

首先饿汉式的单例模式缺陷是非常明显的

  • 饿汉式不管我们使用这个对象与否, 都会在类加载的时期(因为是静态对象)构建一个这样的对象, 但我们想要达成的效果是, 在我们不需要这种类的实例的时候, 我们不去进行构造对象的操作(变主动为被动)来减少内存等相关资源的开销

但是饿汉式单例一定是线程安全的

  • 构建对象的时期是类加载的时候, 后期不同线程对于这个实例的操作也仅仅是涉及到读操作, 不涉及修改操作, 所以当然是线程安全的, 不存在线程安全问题, 但是另一种实现的模式就不一定了

懒汉式单例模式

上面说了饿汉式单例模式的缺陷, 我们尝试使用懒汉式单例的方式去解决这个问题, 也就是仅仅在需要的时候进行new对象的操作

最基础的懒汉单例模式

构造的逻辑

  • 构造方法私有化
  • 提供一个静态的对象用来返回(暂时不new对象)
  • 提供一个公开访问的静态接口来返回唯一的对象

代码测试(最基础的版本)

/*** 下面定义一个类来测试懒汉式单例模式*/
class LazySingleton{// 提供一个静态的变量用来返回private static LazySingleton lazySingleton = null;// 构造方法私有化(不可以在外部new对象)private LazySingleton(){}// 提供一个公开的获取实例的接口public static LazySingleton getInstance(){if(lazySingleton == null){lazySingleton = new LazySingleton();}return lazySingleton;}
}public class DesignPatternTest {public static void main(String[] args) {// 对懒汉式单例的测试LazySingleton instance1 = LazySingleton.getInstance();LazySingleton instance2 = LazySingleton.getInstance();// 测试两者是不是一个对象System.out.println(instance1 == instance2);}
}

基础懒汉式缺陷以及是否线程安全

这个就和上面饿汉有较大的区别了, 虽然解决了在需要的时候进行new对象, 上面的基础版本的懒汉式在单线程的环境下肯定是没问题的, 但是在多线程的环境下就不好说了…看下面的分析

如果在多线程的环境下(我们假设有t1, t2)是下图的执行顺序
在这里插入图片描述
很明显这是一种类似串行的执行策略

但是还可能是下图的情况
在这里插入图片描述
t1线程判断完毕之后没有来得及进行new对象, t2线程紧接着进行了一次完整的new对象的过程, 此时t1线程又进行了一次new对象的过程, 很明显, 我们上面的情况进行了两次构造对象的过程, 同时拿到的对象也不一致

我们通过Thread.sleep()的方式进行延迟观察看是否会发生

/*** 下面定义一个类来测试懒汉式单例模式*/
class LazySingleton{// 提供一个静态的变量用来返回private static LazySingleton lazySingleton = null;// 构造方法私有化(不可以在外部new对象)private LazySingleton(){}// 提供一个公开的获取实例的接口public static LazySingleton getInstance() throws InterruptedException {if(lazySingleton == null){Thread.sleep(1000);lazySingleton = new LazySingleton();}return lazySingleton;}
}public class DesignPatternTest {private static LazySingleton instance1 = null;private static LazySingleton instance2 = null;public static void main(String[] args) throws InterruptedException {// 创建两个线程获取实例Thread t1 = new Thread(() -> {try {instance1 = LazySingleton.getInstance();} catch (InterruptedException e) {e.printStackTrace();}});Thread t2 = new Thread(() -> {try {instance2 = LazySingleton.getInstance();} catch (InterruptedException e) {e.printStackTrace();}});// 开启两个线程t1.start();t2.start();// 睡眠等待一下Thread.sleep(2000);System.out.println(instance1 == instance2);}
}

在这里插入图片描述
很明显, 这样的懒汉式的代码是线程不安全的, 那要如何进行改进呢???

懒汉式单例模式的改进

之前我们说了, 要想保证线程是安全的, 有几种解决方式, 这里面我们就采取加锁, 因为其实
判断是不是null和对象应该是一个整体的原子性的操作

改进之后的代码

/*** 下面定义一个类来测试懒汉式单例模式(改进版)*/
class LazySingleton{// 提供一个静态的变量用来返回private static LazySingleton lazySingleton = null;// 构造方法私有化(不可以在外部new对象)private LazySingleton(){}// 提供一个公开的获取实例的接口public static LazySingleton getInstance() {// 我们把if判断和new对象通过加锁打包为一个原子性的操作(这里使用类对象锁)synchronized (LazySingleton.class){if(lazySingleton == null){lazySingleton = new LazySingleton();}}return lazySingleton;}
}public class DesignPatternTest {private static LazySingleton instance1 = null;private static LazySingleton instance2 = null;public static void main(String[] args) {// 在多线程中获取实例Thread t1 = new Thread(() -> {instance1 = LazySingleton.getInstance();});Thread t2 = new Thread(() -> {instance2 = LazySingleton.getInstance();});System.out.println(instance1 == instance2);}
}

这时候肯定是一个线程安全的代码了, 但是思考可不可以进一步改进呢???


当我们已经new个一次对象之后, 如果后续的线程想要获取这个对象, 那就仅仅是一个操作了, 根本不涉及对对象的修改, 但是我们每次都使用锁这样的机制就会造成阻塞, 也就会导致程序的效率下降, 所以我们对代码进行了下面的修改在外层再加一个if判断

改进的方法如下

// 提供一个公开的获取实例的接口public static LazySingleton getInstance() {// 我们把if判断和new对象通过加锁打包为一个原子性的操作(这里使用类对象锁)if (lazySingleton == null) {synchronized (LazySingleton.class) {if (lazySingleton == null) {lazySingleton = new LazySingleton();}}}return lazySingleton;}

我们的两个if的含义

  • 第一个if: 判断对象是否创建完毕, 如果创建了, 只是一个读操作
  • 第二个if: 判断是不是需要new对象

可能初学多线程的时候, 看上述代码觉得很迷惑, 但其实这是因为之前我们写的程序都是单线程的情况, 单线程中执行流只有一个, 两次相同的if判断其实是没有必要的, 但是多线程的条件下, 是多个执行流, 相同的逻辑判断条件也可能产生不同的结果

完整代码(变量volatile)

关于变量是否会产生指令重排序和内存可见性问题, 我们直接加上volatile即可

/*** 下面定义一个类来测试懒汉式单例模式(完整改进版)*/
class LazySingleton {// 提供一个静态的变量用来返回private volatile static LazySingleton lazySingleton = null;// 构造方法私有化(不可以在外部new对象)private LazySingleton() {}// 提供一个公开的获取实例的接口public static LazySingleton getInstance() {// 我们把if判断和new对象通过加锁打包为一个原子性的操作(这里使用类对象锁)if (lazySingleton == null) {synchronized (LazySingleton.class) {if (lazySingleton == null) {lazySingleton = new LazySingleton();}}}return lazySingleton;}
}

阻塞队列

生产者消费者模型

关于生产者消费者模型, 其实是生活中抽象出来的一个模型案例, 我们举一个包饺子的例子来简单解释一下

  • 在包饺子的过程中, 存在一个擀饺子皮的人, 我们称之为生产者, 擀出来的饺子皮放到一个竹盘上, 这个竹盘相当于一个中间的媒介, 生产者生产的物质在上面与消费者进行交互, 而包饺子的人就是一个消费者, 从中间媒介中取出东西, 也就是消费的过程, 我们的中间的竹盘相当于一个缓冲, 如果包饺子的人包的快的话, 就需要等待做饺子皮的人, 如果做饺子皮的人做的快的话, 当竹盘放不下的时候就需要阻塞等待

  • 上面的情景抽象成生产者消费者模型, 擀饺子皮的人是生产者, 竹盖是阻塞队列, 包饺子的人是消费者

生产者消费者模型的案例以及优点

请求与响应案例

生产者消费者模型我们举一个"请求响应的案例"

在这里插入图片描述
图中我们也有解释, 越靠上游的消耗的资源越少
假设我们现在出现一个秒杀的请求, 上游可能还可以运行, 但是下游的服务器由于并发量过大就直接崩溃了

在这里插入图片描述
所以我们一般会对上面提供服务的逻辑进行改变
添加一个中间的结构(阻塞队列, 或者说消息队列)进行缓冲

在这里插入图片描述


在真实的开发场景当中, 阻塞队列甚至会单独的部署为一台服务器, 这种独立的服务器结构叫做消息队列, 可见其重要性


解耦合

生产者消费者模型的一个重要的优点就是让消费者和生产者解耦合

  • 根据上面的模型分析, 不管是生产者还是消费者都是面向阻塞队列来进行任务的执行的, 所以就降低了两者之间的耦合度, 将来想要修改这个模型的工作内容, 也只需要面向阻塞队列操作更改(其实相当于接口), 如果没有这种机制的话, 我们想要更改一个操作逻辑, 就需要同时修改消费者与生产者的代码结构…, 我们先前学习的接口其实就是一种解耦合的策略, 其核心就是减少耦合度, 便于对代码结构进行调整

削峰填谷

刚才我们的那个模型就说了, 如果消息请求量非常大的时候, 如果没有消息队列的存在, 就会对下游的服务器产生较大的影响, 甚至会导致服务器崩溃


下图是正常情况下消息队列的工作示意图, 添加的任务加入消息队列, 然后下游的服务器以一个相对稳定的效率从队列中取出来任务进行处理
在这里插入图片描述


下图是当任务量激增的时候, 虽然任务量激增, 但是依旧进入消息队列进行等待处理, 此时下游的服务器对任务的处理的效率基本不变, 所以可以保证处理的稳定性, 不至于让下游服务器崩溃, 因为这个消息一般都是一阵一阵的激增, 所以等到下一轮消息量减少的时候, 对先前消息队列的数据进行清理即可…
在这里插入图片描述

阻塞队列的内置API

下图是我们相关的阻塞队列的内置API继承逻辑

在这里插入图片描述


关于构造方法

ArrayBlockingQueue: 必须指定大小
LinkedBlockQueue: 可以指定也可以不指定


关于offerpollputtake的区别

首先是offerpoll

在这里插入图片描述
这两个方法也可以使阻塞队列产生阻塞的效果, 但是我们可以指定一个最大的等待时间
我们使用下面的代码测试

/*** 关于阻塞队列的相关测试*/
public class ThreadTest {public static void main(String[] args) {// 生成一个阻塞队列(指定队列的大小为100)BlockingQueue<Integer> blockingQueue = new ArrayBlockingQueue<Integer>(100);// 创建两个线程测试Thread producer = new Thread(() -> {for(int i = 0; i < 1000; i++){try {blockingQueue.offer(i, 10L, TimeUnit.SECONDS);System.out.println("生产了元素: " + i);} catch (InterruptedException e) {e.printStackTrace();}}});// 消费者线程Thread consumer = new Thread(() -> {while(true){try {// 进行休眠Thread.sleep(1000 * 1);int elem = blockingQueue.take();System.out.println("消费了元素: " + elem);} catch (InterruptedException e) {e.printStackTrace();}}});producer.start();consumer.start();}
}

分析下这个程序的执行的逻辑

  • 在程序启动的很短的时间内, 由于阻塞队列的容量还有空余, 所以会大量的生产元素直到阻塞队列满了, 因为消费者线程是每一秒钟消耗一个元素, 所以存在等待时间, 我们上述代码设置的最大的等待时间是10s, 所以根本来不及等待到最大的时间点就可以进行取出元素…

puttake方法

  • 这组方法和上组方法的区别就是, 这个方法是当队列满或者队列空, 我们进行无限期的阻塞…, 直到队列中的元素不为空或者不为满就可以进行操作
/*** 关于阻塞队列的相关测试*/
public class ThreadTest {public static void main(String[] args) {// 生成一个阻塞队列(指定队列的大小为100)BlockingQueue<Integer> blockingQueue = new ArrayBlockingQueue<Integer>(100);// 创建两个线程测试Thread producer = new Thread(() -> {for(int i = 0; i < 1000; i++){try {blockingQueue.put(i);System.out.println("生产了元素: " + i);} catch (InterruptedException e) {e.printStackTrace();}}});// 消费者线程Thread consumer = new Thread(() -> {while(true){try {// 进行休眠Thread.sleep(1000 * 1);int elem = blockingQueue.take();System.out.println("消费了元素: " + elem);} catch (InterruptedException e) {e.printStackTrace();}}});producer.start();consumer.start();}
}

最后的执行结果如下

在这里插入图片描述
在短时间之内进行大量的生产之后开始隔一秒拿出一个元素, 生产一个元素

阻塞队列的模拟实现

关于wait和while的搭配使用

在这里插入图片描述
上面是我们的JDK帮助文档wait使用的建议(其实就是源码), 我们官方文档中提倡wait的使用建议和while循环搭配, 而不是和if搭配…原因下面解释

模拟实现

其实就是一个循环队列, 在put方法加入元素的时候如果队列是满的就进行阻塞, 在take方法拿出元素的时候如果队列是空的也进行阻塞(使用wait), 然后put方法添加了一个元素之后, 使用notify方法对take正在阻塞的线程进行唤醒(随机唤醒), 下面是实现代码


/*** 自己实现一个阻塞队列* 1. 使用循环数组* 2. 使用wait-notify进行线程见的通信* 3. 关于wait的使用的while机制*/
public class MyBlockingQueue {// 我们定义这个阻塞队列中的元素是int类型private int capacity = 0;private int[] queue = null;// 构造方法public MyBlockingQueue(int capacity) {this.capacity = capacity;queue = new int[capacity];}// 定义队首尾的指针以及元素个数private int first = 0;private int last = 0;private int size = 0;// 判断队列是否为空private boolean isEmpty() {return size == 0;}// 判断队列是否是满的private boolean isFull() {return size == capacity;}// put操作public void put(int val) throws InterruptedException {while (isFull()) {// 此时进入阻塞等待synchronized (this) {this.wait();}}queue[last] = val;last = (last + 1) % capacity;size++;// 随机唤醒一个线程synchronized (this) {this.notify();}}// take操作public int take() throws InterruptedException {while (isEmpty()) {// 此时进入阻塞等待synchronized (this) {this.wait();}}int res = queue[first];first = (first + 1) % capacity;size--;// 随机唤醒一个线程synchronized (this) {this.notify();}return res;}
}class Test {public static void main(String[] args) {// 对实现的队列进行测试MyBlockingQueue myBlockingQueue = new MyBlockingQueue(100);// 创建生产者线程进行测试Thread producer = new Thread(() -> {for(int i = 0; i < 1000; i++){try {myBlockingQueue.put(i);System.out.println("生产了元素: " + i);} catch (InterruptedException e) {e.printStackTrace();}}});// 创建消费者线程进行测试Thread consumer = new Thread(() -> {for(int i = 0; i < 1000; i++){try {Thread.sleep(1000);int getElem = myBlockingQueue.take();System.out.println("消费了元素: " + getElem);} catch (InterruptedException e) {e.printStackTrace();}}});// 启动两个线程producer.start();consumer.start();}
}

在这里插入图片描述
瞬间产出100个元素之后进行阻塞, 产出一个消耗一个…


为什么要使用while代替if

 // put操作public void put(int val) throws InterruptedException {if(isFull()) {// 此时进入阻塞等待synchronized (this) {this.wait();}}queue[last] = val;last = (last + 1) % capacity;size++;// 随机唤醒一个线程synchronized (this) {this.notify();}}// put操作public void put(int val) throws InterruptedException {while (isFull()) {// 此时进入阻塞等待synchronized (this) {this.wait();}}queue[last] = val;last = (last + 1) % capacity;size++;// 随机唤醒一个线程synchronized (this) {this.notify();}}

我们分析一下两个相同的操作, 使用whileif的区别

在这里插入图片描述
这一张图片揭示了为什么使用wait搭配while使用更加合理

相关文章:

JavaEE-经典多线程样例

文章目录 单例模式设计模式初步引入为何存在单例模式饿汉式单例模式饿汉式缺陷以及是否线程安全懒汉式单例模式基础懒汉式缺陷以及是否线程安全懒汉式单例模式的改进完整代码(变量volatile) 阻塞队列生产者消费者模型生产者消费者模型的案例以及优点请求与响应案例解耦合削峰填…...

Android显示系统(04)- OpenGL ES - Shader绘制三角形

一、前言&#xff1a; OpenGL 1.0采用固定管线&#xff0c;OpenGL 2.0以上版本重要的改变就是采用了可编程管线&#xff0c;Shader 编程是指使用着色器&#xff08;Shader&#xff09;编写代码来控制图形渲染管线中特定阶段的处理过程。在图形渲染中&#xff0c;着色器是在 GP…...

PMP–一、二、三模、冲刺–分类–10.沟通管理

文章目录 技巧十、沟通管理 一模10.沟通管理--1.规划沟通管理--文化意识--军事背景和非军事背景人员有文化差异5、 [单选] 项目团队由前军事和非军事小组成员组成。没有军事背景的团队成员认为前军事团队成员在他们的项目方法中过于结构化和僵化。前军事成员认为其他团队成员更…...

flutter windows 使用c++、dll等实践记录

在flutter的windows平台引入dll文件 https://juejin.cn/post/7223676609794015287 google官方说法&#xff08;感觉不太实用&#xff09; https://groups.google.com/a/dartlang.org/g/misc/c/fyh2W38AEVo Using a C DLL in Flutter Windows desktop app&#xff08;未尝试&…...

JUnit介绍:单元测试

1、什么是单元测试 单元测试是针对最小的功能单元编写测试代码&#xff08;Java 程序最小的功能单元是方法&#xff09;单元测试就是针对单个Java方法的测试。 2、为什么要使用单元测试 确保单个方法运行正常&#xff1b; 如果修改了代码&#xff0c;只需要确保其对应的单元…...

电脑插入耳机和音响,只显示一个播放设备

1. 控制面板-硬件和声音-Realtek高清音频-扬声器-设备高级设置-播放设备里选择使用前部和后部输出设备同时播放两种不同的音频流 在声音设置中就可以看到耳机播放选项...

【每日刷题】Day162

【每日刷题】Day162 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;每日刷题&#x1f34d; &#x1f33c;文章目录&#x1f33c; 1. 3302. 字典序最小的合法序列 - 力扣&#xff08;LeetCode&#xff09; 2. 44. 通配符匹配 - 力扣&…...

使用 EasyExcel 实现高效的 Excel 读写操作

在日常开发中&#xff0c;Excel 文件的读写操作是一个常见的需求。EasyExcel 是阿里巴巴开源的一个高性能、易用的 Excel 读写库&#xff0c;可以大幅提高处理 Excel 文件的效率。它通过事件驱动模型优化了大数据量 Excel 的读写性能&#xff0c;非常适合处理大文件或高并发场景…...

千益畅行,旅游卡有些什么优势?

千益畅行共享旅游卡是一种创新的旅游服务模式&#xff0c;旨在通过整合各类旅游资源&#xff0c;为用户提供一站式的旅游解决方案。这张旅游卡支持2至6人同行&#xff0c;涵盖了接机、酒店、用餐、大巴、导游、景区门票等服务&#xff0c;用户只需自行承担往返交通费用即可享受…...

Hive分区裁剪(Partition Pruning)详解

Hive分区裁剪是一种优化技术&#xff0c;旨在查询时只读取与条件匹配的分区&#xff0c;从而减少不必要的数据扫描。这种机制依赖于分区表的设计和查询优化器的工作&#xff0c;特别是在处理大规模数据时&#xff0c;分区裁剪可以显著提高查询性能。 1. 什么是分区裁剪&#xf…...

云原生数据库 PolarDB

PolarDB 是阿里云推出的一款云原生数据库&#xff0c;旨在为企业提供高性能、高可靠性的数据库解决方案。它基于云计算环境设计&#xff0c;特别适用于云上的大规模数据处理和存储需求。PolarDB 是一种兼具关系型数据库&#xff08;RDS&#xff09;和分布式数据库特性的新型数据…...

数据库原理-期末基础知识

1、数据库管理系统有哪些功能&#xff1f; 数据定义功能、数据操作功能、数据库的运行管理、数据库的建立与维护。 2、数据库设计分哪几个阶段&#xff1f; 需求分析->概念设计->逻辑设计->物理设计->数据库实施->数据的运营与维护 3、简述三级封锁协议的内…...

Java版-速通数据结构-树基础知识

现在面试问mysql,红黑树好像都是必备问题了。动不动就让手写红黑树或者简单介绍下红黑树。然而&#xff0c;我们如果直接去看红黑树&#xff0c;可能会一下子蒙了。在看红黑树之前&#xff0c;需要先了解下树的基础知识&#xff0c;从简单到复杂&#xff0c;看看红黑树是在什么…...

量化交易系统开发-实时行情自动化交易-8.4.MT4/MT5平台

19年创业做过一年的量化交易但没有成功&#xff0c;作为交易系统的开发人员积累了一些经验&#xff0c;最近想重新研究交易系统&#xff0c;一边整理一边写出来一些思考供大家参考&#xff0c;也希望跟做量化的朋友有更多的交流和合作。 接下来会对于MT4/MT5平台介绍。 MetaT…...

Git 的基本概念和使用方式

Git是一个分布式版本控制系统&#xff0c;用于跟踪文件内容的变化和协作开发。 Git的主要概念包括&#xff1a; 仓库&#xff08;Repository&#xff09;&#xff1a;存储代码和历史记录的地方。可以是本地仓库&#xff08;Local Repository&#xff09;或远程仓库&#xff08…...

Conda-Pack打包:高效管理Python环境

在Python开发中&#xff0c;环境管理是一个不可忽视的重要环节。Conda是一个流行的包管理器和环境管理器&#xff0c;它允许用户创建隔离的环境&#xff0c;以避免不同项目之间的依赖冲突。Conda-pack是一个工具&#xff0c;可以帮助我们将一个conda环境打包成一个可移植文件&a…...

Python语法基础---正则表达式

&#x1f308;个人主页&#xff1a;羽晨同学 &#x1f4ab;个人格言:“成为自己未来的主人~” 我们这个文章所讲述的&#xff0c;也是数据分析的基础文章&#xff0c;正则表达式 首先&#xff0c;我们在开始之前&#xff0c;引出一个问题。也是我们接下来想要解决的问题。…...

深入理解ROS中的参数服务器及其应用

深入理解ROS中的参数服务器及其应用 在Robot Operating System (ROS) 中&#xff0c;参数服务器&#xff08;Parameter Server&#xff09;是一个中心化服务&#xff0c;它允许节点在运行时存储和检索配置信息。这种机制是为了支持数据的共享和灵活的参数管理而设计的&#xf…...

Kafka 常见面试题深度解析

一、基础概念 1. 请简要介绍 Kafka 的基本架构。 Kafka 主要由生产者&#xff08;Producer&#xff09;、消费者&#xff08;Consumer&#xff09;、代理&#xff08;Broker&#xff09;、主题&#xff08;Topic&#xff09;和分区&#xff08;Partition&#xff09;等组成。…...

数学建模之熵权法

熵权法 概述 **熵权法(Entropy Weight Method,EWM)**是一种客观赋权的方法&#xff0c;原理&#xff1a;指标的变异程度越小&#xff0c;所包含的信息量也越小&#xff0c;其对应的权值应该越低&#xff08;例如&#xff0c;如果对于所有样本而言&#xff0c;某项指标的值都相…...

交易所 Level-2 历史行情数据自动化导入攻略

用户部署完 DolphinDB 后&#xff0c;需要将历史股票数据批量导入数据库&#xff0c;再进行数据查询、计算和分析等操作。DolphinDB 开发了 ExchData 模块&#xff0c;主要用于沪深交易所 Level-2 行情原始数据的自动化导入&#xff0c;目前已支持的数据源包括&#xff1a; 沪…...

从 scratch开始构建一个最小化的 Hello World Docker 镜像-docker的镜像源头

在这篇文章中&#xff0c;我们将学习如何从零开始构建一个最小化的 Docker 镜像&#xff0c;基于 scratch 镜像&#xff0c;并在其中运行一个简单的 “Hello World” 程序。 Scratch 是一个空白的基础镜像&#xff0c;适用于构建轻量化、独立的容器。由于 scratch 不包含任何系…...

【openGauss︱PostgreSQL】openGauss或PostgreSQL查表、索引、序列、权限、函数

【openGauss︱PostgreSQL】openGauss或PostgreSQL查表、索引、序列、权限、函数 一、openGauss查表二、openGauss查索引三、openGauss查序列四、openGauss查权限五、openGauss或PostgreSQL查函数六、PostgreSQL查表七、PostgreSQL查索引八、PostgreSQL查序列九、PostgreSQL查权…...

MySQL - 性能优化

使用 Explain 进行分析 Explain 用来分析 SELECT 查询语句&#xff0c;开发人员可以通过分析 Explain 结果来优化查询语句。 比较重要的字段有: select_type : 查询类型&#xff0c;有简单查询、联合查询、子查询等 key : 使用的索引 rows : 扫描的行数 type &#xff1a;…...

数据结构:二叉树遍历

在 JavaScript 中实现二叉树的遍历&#xff0c;可以使用递归或迭代的方式。以下是三种常见的遍历方式&#xff1a;前序遍历&#xff08;Pre-order&#xff09;、中序遍历&#xff08;In-order&#xff09;和后序遍历&#xff08;Post-order&#xff09;。 定义二叉树节点类 c…...

【热门主题】000075 探索嵌入式硬件设计的奥秘

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 【热…...

mac启动jmeter

// 设置使用java8&#xff0c;使用21版本会有问题 export JAVA_HOME/Library/Java/JavaVirtualMachines/jdk1.8.0_221.jdk/Contents/Home/ export PATH$JAVA_HOME/bin:$PATH cd /Users/user/software/apache-jmeter-5.1.1 //设置不使用代理 sh jmeter -Jhttp.proxyHost -J…...

JavaScript的作用域与闭包

文章目录 一. 什么是作用域?二. var a 2是如何赋值并添加到作用域中的?三. 作用域链四. js中的各种作用域五. 闭包?六. 参考 今天开始读了《你所不知道的JavaScript(上卷)》的一部分, 自己对于 JS 的理解还是非常浅薄的; 本着学习与分享的目的, 对这本书的第一章的内容进行…...

Qt入门7——Qt事件

目录 1. Qt事件介绍&#xff1a; 2. 事件的处理 示例1&#xff1a;鼠标进入(enterEvent)与离开事件(leaveEvent) 示例2&#xff1a;鼠标点击事件(mousePressEvent) 示例3&#xff1a;鼠标移动事件(mouseMoveEvent) 3. 按键事件 4. 定时器 5. 窗口事件 1. Qt事件介绍&a…...

【Linux操作系统】多线程控制(创建,等待,终止、分离)

目录 一、线程与轻量级进程的关系二、进程创建1.线程创建线程创建函数&#xff08;pthread&#xff09;查看和理解线程id主线程与其他线程之间的关系 三、线程等待&#xff08;回收&#xff09;四、线程退出线程退出情况线程退出方法 五、线程分离线程的优点线程的缺点 一、线程…...

VR眼镜可视化编程:开启医疗信息系统新纪元

一、引言 随着科技的飞速发展&#xff0c;VR 可视化编程在医疗信息系统中的应用正逐渐成为医疗领域的新趋势。它不仅为医疗教育、手术培训、疼痛管理等方面带来了新的机遇&#xff0c;还在提升患者体验、推动医疗信息系统智能化等方面发挥着重要作用。 在当今医疗领域&#xf…...

数据结构自测题6

第7章 图 自测卷解答 一、单选题&#xff08;每题1分&#xff0c;共16分&#xff09; &#xff08; C &#xff09;1. 在一个图中&#xff0c;所有顶点的度数之和等于图的边数的 倍。 A&#xff0e;1/2 B. 1 C. 2 D. 4 &#xff08; B &#xff09;2. 在一个有向图中&#xff0…...

Marvell第四季度营收预计超预期,定制芯片需求激增

芯片制造商Marvell Technology&#xff08;美满电子科技&#xff09;&#xff08;MRVL&#xff09;在周二发布了强劲的业绩预告&#xff0c;预计第四季度的营收将超过市场预期&#xff0c;得益于企业对其定制人工智能芯片的需求激增。随着人工智能技术的快速发展&#xff0c;特…...

从智能合约到去中心化AI:Web3的技术蓝图

Web3正在成为互联网发展的重要方向&#xff0c;其核心理念是去中心化、用户主权和自治。随着区块链技术、智能合约以及人工智能&#xff08;AI&#xff09;等技术的发展&#xff0c;Web3不仅重新定义了数据存储和交易方式&#xff0c;还为更智能化、去中心化的数字生态系统铺平…...

opencvocr识别手机摄像头拍摄的指定区域文字,文字符合规则就语音报警

安装python&#xff0c;pycharm&#xff0c;自行安装。 Python下安装OpenCv 2.1 打开cmd,先安装opencv-python pip install opencv-python --user -i https://pypi.tuna.tsinghua.edu.cn/simple2.2 再安装opencv-contrib-python pip install opencv-contrib-python --user …...

python 笔记之线程同步和死锁

同步&#xff1a; 共享数据&#xff1a; 如果多个线程共同对某个数据修改&#xff0c;则可能出现不可预测的结果&#xff0c;为了保证数据的正确性&#xff0c;需要对多个数据进行同步 同步&#xff1a;一个一个的完成&#xff0c;一个做完另一个才能进来 效率会降低 使用Thre…...

解决Error resolving plugin xxx

问题信息 Error resolving plugin [id: com.android.library, version: 8.6.0] > The request for this plugin could not be satisfied because the plugin is already on the classpath with an unknown version, so compatibility cannot be checked.* Try: > Run wi…...

Word2vec、词向量是什么? |Gensim中word2vec模型的参数定义

前言&#xff1a; 最近在忙毕设&#xff0c;要学习一些AI的技术。很多资料看来看去&#xff0c;感觉只是在大脑皮层表面略过了一下&#xff0c;遂还是决定采用老方法&#xff0c;写博客&#xff01;&#xff01;&#xff01;对了&#xff0c;我也只是一个萌新&#xff0c;博客的…...

<工具 Claude Desktop> 配置 MCP server 连接本地 SQLite, 本机文件夹(目录) 网络驱动器 Windows 11 系统

也是在学习中... 起因&#xff1a; 抖音博客 艾克AI分享 他的视频 #143《Claude开源MCP彻底打破AI的信息孤岛》 提到: Claude开源的MCP太强了&#xff0c;视频后面是快速演示&#xff0c;反正看了好几遍也没弄明白。菜单都不一样&#xff0c;感觉用的不是同一家 Claude. 探…...

Android10 设备死机的问题分析和解决

最近客户反馈一个问题&#xff0c;设备偶现死机。最后解决&#xff0c;在此记录。 目录 一死机的现象 二死机的类型 三 死机问题分析 1 死机现象的梳理 2 死机日志 1&#xff09;日志分析一 2 日志分析二&#xff08;正确方案&#xff09; 一死机的现象 设备死机&#x…...

Linux操作系统性能优化

Linux操作系统性能优化 1. TCP连接出现大量ESTABLISHED连接解决方法 1. TCP连接出现大量ESTABLISHED连接解决方法 TCP协议规定&#xff0c;对于已经建立的连接&#xff0c;网络双方要进行四次握手才能成功断开连接&#xff0c;如果缺少了其中某个步骤&#xff0c;将会使连接处于…...

【图像处理】用Python和OpenCV实现简单的图像增强与特征提取

《Python OpenCV从菜鸟到高手》带你进入图像处理与计算机视觉的大门! 图像处理是计算机视觉领域的重要基础,而图像增强和特征提取是其中的关键技术。本文将详细探讨如何使用 Python 和 OpenCV 实现图像增强与特征提取。通过具体示例,我们将介绍滤波、直方图均衡化、边缘检测…...

【技术学习网站】

小黄鸭&#xff1a;面试鸭 - 程序员求职面试刷题神器&#xff0c;高频编程题目免费刷 编程导航&#xff1a;编程导航 - 程序员一站式编程学习交流社区&#xff0c;做您编程学习路上的导航员 博客园&#xff1a;博客园 - 开发者的网上家园 前端开发&#xff1a;HTTP 缓存 - H…...

程序员需要具备哪些知识?

程序员需要掌握的知识广泛而深厚&#xff0c;这主要取决于具体从事的领域和技术方向。不过&#xff0c;有些核心知识是共通的&#xff0c;就像建房子的地基一样&#xff0c;下面来讲讲这些关键领域&#xff1a; 1. 编程语言&#xff1a; 无论你是搞前端、后端、移动开发还是嵌…...

架构10-可观测性

零、文章目录 架构10-可观测性 1、可观测性 &#xff08;1&#xff09;可观测性的背景 **历史沿革&#xff1a;**可观测性最初由匈牙利数学家鲁道夫卡尔曼提出&#xff0c;用于线性动态控制系统。后来&#xff0c;该概念被引入到计算机科学中。**现代意义&#xff1a;**在分…...

Active RIS-Aided ISAC Systems: Beamforming Design and Performance Analysis

文章目录 II. SYSTEM MODELC. Active RIS Model III. PROBLEM FORMULATIONA. Radar Performance MetricC. Optimize Φ V. PERFORMANCE ANALYSIS OF THE RADAR SINR IN ACTIVE RIS-AIDED SENSING SYSTEMSA. Simplified System SettingB. Power Scaling Law AnalysisC. Active R…...

oracle 11g中如何快速设置表分区的自动增加

在很多业务系统中&#xff0c;一些大表一般通过分区表的形式来实现数据的分离管理&#xff0c;进而加快数据查询的速度。分区表运维管理的时候&#xff0c;由于人为操作容易忘记添加分区&#xff0c;导致业务数据写入报错。所以我们一般通过配置脚本或者利用oracle内置功能实现…...

HCIA-openGauss_1_4基本功能介绍

openGauss支持标准SQL SQL是用于访问和处理数据库的标准计算机语言&#xff0c;SQL标准的定义分成核心特性以及可选特性&#xff0c;绝大部分的数据库都没有100%支撑SQL标准。openGuass支持SQL2003标准语法&#xff0c;支持主备部署的高性能可用关系型数据库。openGauss数据库…...

el-menu导航三级数据结构及数据展示

1:数据展示 <el-col><el-menu:default-active"$route.path"class"el-menu-vertical-demo"routerunique-openedbackground-color"#545c64"text-color"#fff"active-text-color"#ffd04b"><div v-for"item …...

全面解析 Transformer:改变深度学习格局的神经网络架构

目录 一、什么是 Transformer&#xff1f; 二、Transformer 的结构解析 1. 编码器&#xff08;Encoder&#xff09; 2. 解码器&#xff08;Decoder&#xff09; 3. Transformer 模型结构图 三、核心技术&#xff1a;注意力机制与多头注意力 1. 注意力机制 2. 多头注意力&…...