常用并发设计模式
避免共享的设计模式
不变性(Immutability)模式,写时复制(Copy-on-Write)模式,线程本地存储(Thread-Specific
Storage)模式本质上都是为了避免共享。
1、使用时需要注意不变性模式的属性的不可变性。
2、写时复制模式需要注意拷贝的性能问题。
3、线程本地存储模式需要注意异步执行问题。
不变性(Immutability)模式——想破坏也破坏不了
“多个线程同时读写同一共享变量存在并发问题”,这里的必要条件之一是读写,如果只有读,而没
有写,是没有并发问题的。解决并发问题,其实最简单的办法就是让共享变量只有读操作,而没有写操作。这个办法如此重要,以至于被上升到了一种解决并发问题的设计模式:不变性(Immutability)模式。
不变性模式是一种创建不可变对象的设计模式,即对象一旦创建后,就不能再进行修改。在多线程
环境下,使用不可变对象可以避免线程安全问题,并提高程序的性能和可读性。
使用不变性模式可以带来多种好处,例如:
1、线程安全性:不可变对象在多线程环境下不需要进行同步操作,可以避免线程安全问题。
2、可读性:不可变对象的状态在创建后不可修改,可以更加清晰地表达对象的含义和作用。
3、性能:由于不可变对象的状态不可变,可以进行更加有效的缓存和优化操作。
3、可测试性:不可变对象对单元测试非常友好,可以更容易地进行测试和验证。
不变性模式虽然有很多优点,但也有一些限制。例如,不可变对象的状态一旦创建后就无法修改,需要重新创建一个新的对象。因此,在需要频繁修改对象状态的场景下,不可变对象可能不太适用。同时,在不可变对象之间存在引用关系的情况下,需要注意对象状态的变化。
使用场景
不变性模式适用于需要确保对象状态不变的场景,例如:
1、缓存:在缓存系统中,需要缓存一些数据,以避免重复计算和频繁访问。由于缓存数据是共享的,为了避免数据被修改,通常使用不变性模式来确保缓存数据的不变性。
2、值对象:在一些系统中,需要定义一些值对象来表示一些常量或者不可变的对象。使用不变性模式可以确保这些值对象的状态不变,从而避免出现错误和不一致。
3、配置信息:在一些系统中,需要读取一些配置信息来配置系统参数和行为。由于配置信息通常是不变的,可以使用不变性模式来确保配置信息的不变性。
如何实现不变性模式
不变性模式的主要思想是通过将对象的状态设置为final和私有,并提供只读方法来保证对象的不可变性。在创建不可变对象时,需要确保对象的所有属性都是不可变的,即在创建后不会被修改。同时,还需要注意不可变对象之间的引用关系,以避免出现对象的状态变化。
jdk中很多类都具备不可变性,例如经常用到的 String 和 Long、Integer、Double 等基础类型的包装类都具备不可变性,这些对象的线程安全性都是靠不可变性来保证的。它们都严格遵守了不可变类的三点要求:类和属性都是 final 的,所有方法均是只读的。
代码示例:
/*** 短信服务商信息*/
public class SmsInfo {/*** 短信服务商请求url*/private String url;/*** 每次发送短信内容的最大字节数*/private Integer maxSizeInBytes;public SmsInfo(String url, Integer maxSizeInBytes) {this.url = url;this.maxSizeInBytes = maxSizeInBytes;}public String getUrl() {return url;}public void setUrl(String url) {this.url = url;}public void setMaxSizeInBytes(Integer maxSizeInBytes) {this.maxSizeInBytes = maxSizeInBytes;}@Overridepublic String toString() {return "SmsInfo{" +"url='" + url + '\'' +", maxSizeInBytes=" + maxSizeInBytes +'}';}
}
public class SmsDemo {public static void main(String[] args) throws InterruptedException {// 创建短信服务商的信息SmsInfo smsInfo = new SmsInfo("https://www.aliyun.com", 180);new Thread(new Runnable() {@Overridepublic void run() {smsInfo.setUrl("https://cloud.tencent.com");try {Thread.sleep(100);} catch (InterruptedException e) {throw new RuntimeException(e);}smsInfo.setMaxSizeInBytes(200);}}, "线程1").start();// 线程2读取短信服务商信息new Thread(new Runnable() {@Overridepublic void run() {System.out.println("线程2获取短信服务商信息:" + smsInfo);}}, "线程2").start();}
}
执行结果:
线程2获取短信服务商信息:SmsInfo{url='https://cloud.tencent.com', maxSizeInBytes=180}
发现线程2读取的最大字节数不正确。
因为配置一般都是不变的,所以改造之后的代码示例:
/*** 短信服务商信息*/
public class SmsInfo {/*** 短信服务商请求url*/private final String url;/*** 每次发送短信内容的最大字节数*/private final Integer maxSizeInBytes;public SmsInfo(String url, Integer maxSizeInBytes) {this.url = url;this.maxSizeInBytes = maxSizeInBytes;}public String getUrl() {return url;}public SmsInfo update(String url, Integer maxSizeInBytes) {return new SmsInfo(url, maxSizeInBytes);}public Integer getMaxSizeInBytes() {return maxSizeInBytes;}@Overridepublic String toString() {return "SmsInfo{" +"url='" + url + '\'' +", maxSizeInBytes=" + maxSizeInBytes +'}';}
}
public class SmsDemo {public static void main(String[] args) throws InterruptedException {// 创建短信服务商的信息SmsInfo smsInfo = new SmsInfo("https://www.aliyun.com", 180);new Thread(new Runnable() {@Overridepublic void run() {smsInfo.update("https://cloud.tencent.com", 200);}}, "线程1").start();// 线程2读取短信服务商信息new Thread(new Runnable() {@Overridepublic void run() {System.out.println("线程2获取短信服务商信息:" + smsInfo);}}, "线程2").start();}
}
执行结果:
线程2获取短信服务商信息:SmsInfo{url='https://www.aliyun.com', maxSizeInBytes=180}
将属性改为final,如果要修改可以加个update方法返回新的对象,这样获取结果就还是原来的。
使用 Immutability 模式的注意事项
在使用 Immutability 模式的时候,需要注意以下两点:
1、对象的所有属性都是 final 的,并不能保证不可变性。
2、不可变对象也需要正确发布。
在 Java 语言中,final 修饰的属性一旦被赋值,就不可以再修改,但是如果属性的类型是普通对象,那么这个普通对象的属性是可以被修改的。所以,在使用 Immutability 模式的时候一定要确认保持不变性的边界在哪里,是否要求属性对象也具备不可变性。
下面的代码中,Bar 的属性 foo 虽然是 final 的,依然可以通过 setAge() 方法来设置 foo 的属性 age。
class Foo {int age = 0;String name = "abc";
}
final class Bar {final Foo foo;Bar(Foo foo) {this.foo = foo;}void setAge(int a) {foo.age = a;}
}
不可变对象虽然是线程安全的,但是并不意味着引用这些不可变对象的对象就是线程安全的。
下面的代码中,Foo 具备不可变性,线程安全,但是类 Bar 并不是线程安全的,类 Bar 中持有对
Foo 的引用 foo,对 foo 这个引用的修改在多线程中并不能保证可见性和原子性。
final class Foo {final int age = 0;final String name = "abc";
}
class Bar {Foo foo;void setFoo(Foo f) {this.foo = f;}
}
写时复制(Copy-on-Write)模式
在多线程环境下,Copy-on-Write模式可以提高共享数据的并发性能。该模式的基本思想是在共享数据被修改时,先将数据复制一份,然后对副本进行修改,最后再将副本替换为原始的共享数据。通过这种方式,可以避免多个线程同时访问同一个共享数据造成的竞争和冲突。
不可变对象的写操作往往都是使用 Copy-on-Write 方法解决的,当然 Copy-on-Write 的应用领域并不局限于 Immutability 模式。
Copy-on-Write 才是最简单的并发解决方案,很多人都在无意中把它忽视了。它是如此简单,以至于 Java 中的基本数据类型 String、Integer、Long 等都是基于 Copy-on-Write 方案实现的。
Copy-on-Write 缺点就是消耗内存,每次修改都需要复制一个新的对象出来,好在随着自动垃圾回收(GC)算法的成熟以及硬件的发展,这种内存消耗已经渐渐可以接受了。所以在实际工作中,如果写操作非常少(读多写少的场景),可以尝试使用 Copy-on-Write。
使用场景
在Java中,CopyOnWriteArrayList 和 CopyOnWriteArraySet 这两个 Copy-on-Write 容器,它们背后的设计思想就是 Copy-on-Write;通过 Copy-on-Write 这两个容器实现的读操作是无锁的,由于无锁,所以将读操作的性能发挥到了极致。
Copy-on-Write 在操作系统领域也有广泛的应用。类 Unix 的操作系统中创建进程的 API 是 fork(),传统的 fork() 函数会创建父进程的一个完整副本,例如父进程的地址空间现在用到了 1G 的内存,那么fork() 子进程的时候要复制父进程整个进程的地址空间(占有 1G 内存)给子进程,这个过程是很耗时的。而 Linux 中fork() 子进程的时候,并不复制整个进程的地址空间,而是让父子进程共享同一个地址空间;只用在父进程或者子进程需要写入的时候才会复制地址空间,从而使父子进程拥有各自的地址空间。
Copy-on-Write 最大的应用领域还是在函数式编程领域。函数式编程的基础是不可变性(Immutability),所以函数式编程里面所有的修改操作都需要 Copy-on-Write 来解决。
像一些RPC框架还有服务注册中心,也会利用Copy-on-Write设计思想维护服务路由表。路由表是典型的读多写少,而且路由表对数据的一致性要求并不高,一个服务提供方从上线到反馈到客户端的路由表里,即便有 5 秒钟延迟,很多时候也都是能接受的。
线程本地存储(Thread-Specific Storage) 模式——没有共享就没有伤害
线程本地存储模式用于解决多线程环境下的数据共享和数据隔离问题。该模式的基本思想是为每个线程创建独立的存储空间,用于存储线程私有的数据。通过这种方式,可以保证线程之间的数据隔离和互不干扰。在 Java 标准类库中,ThreadLocal 类实现了该模式。
线程本地存储模式本质上是一种避免共享的方案,由于没有共享,所以自然也就没有并发问题。如果你需要在并发场景中使用一个线程不安全的工具类,最简单的方案就是避免共享。避免共享有两种方案,一种方案是将这个工具类作为局部变量使用,另外一种方案就是线程本地存储模式。这两种方案,局部变量方案的缺点是在高并发场景下会频繁创建对象,而线程本地存储方案,每个线程只需要创建一个工具类的实例,所以不存在频繁创建对象的问题。
使用场景
线程本地存储模式通常用于以下场景:
保存上下文信息:在多线程环境中,每个线程都有自己的执行上下文,包括线程的状态、环境变量、运行时状态等。线程本地存储可以用来保存这些上下文信息,使得每个线程都可以独立地访问和修改自己的上下文信息。
管理线程安全对象:在多线程环境中,共享对象通常需要进行同步操作以避免竞争条件。但是,有些对象是线程安全的,可以被多个线程同时访问而不需要同步操作。线程本地存储可以用来管理这些线程安全对象,使得每个线程都可以独立地访问自己的对象实例,而不需要进行同步操作。
实现线程特定的行为:有些应用程序需要在每个线程中执行特定的行为,例如跟踪日志、统计数据、授权访问等。线程本地存储可以用来实现这些线程特定的行为,使得每个线程都可以独立地执行自己的行为逻辑,而不需要与其他线程进行协调。
需要注意的是,线程本地存储虽然可以提高性能,但也可能会导致内存泄漏和数据一致性问题。因
此,在使用线程本地存储时,需要仔细考虑数据的生命周期和线程的使用情况,避免出现潜在的问
题。
注意:在线程池中使用ThreadLocal 需要避免内存泄漏和线程安全的问题。
多线程版本的if模式
守护挂起(Guarded Suspension)模式和避免执行(Balking)模式属于多线程版本的if模式
1、守护挂起模式需要注意性能。
2、避免重复执行模式需要注意竞态问题。
守护挂起(Guarded Suspension)模式
守护挂起模式是通过让线程等待来保护实例的安全性,即守护-挂起模式。在多线程开发中,常常为了提高应用程序的并发性,会将一个任务分解为多个子任务交给多个线程并行执行,而多个线程之间相互协作时,仍然会存在一个线程需要等待另外的线程完成后继续下一步操作。而Guarded Suspension模式可以帮助我们解决上述的等待问题。
守护挂起模式允许多个线程对实例资源进行访问,但是实例资源需要对资源的分配做出管理。
守护挂起模式也常被称作 Guarded Wait 模式、Spin Lock 模式(因为使用了 while 循环去等
待),它还有一个更形象的非官方名字:多线程版本的 if。
1、有一个结果需要从一个线程传递到另一个线程,让他们关联同一个 GuardedObject。
2、如果有结果不断从一个线程到另一个线程那么可以使用消息队列。
3、JDK 中,join 的实现、Future 的实现,采用的就是此模式。
4、因为要等待另一方的结果,因此归类到同步模式。
等待唤醒机制的规范实现。此模式依赖于Java线程的等待唤醒机制:
1、synchronized+wait/notify/notifyAll
2、reentrantLock+Condition(await/singal/singalAll)
3、cas+park/unpark
使用场景
1、多线程环境下多个线程访问相同实例资源,从实例资源中获得资源并处理。
2、实例资源需要管理自身拥有的资源,并对请求线程的请求作出允许与否的判断。
避免执行(Balking)模式
Balking是“退缩不前”的意思。如果现在不适合执行这个操作,或者没必要执行这个操作,就停止处理,直接返回。当流程的执行顺序依赖于某个共享变量的场景,可以归纳为多线程if模式。Balking 模式常用于一个线程发现另一个线程已经做了某一件相同的事,那么本线程就无需再做了,直接结束返回。
Balking模式是一种多个线程执行同一操作A时可以考虑的模式;在某一个线程B被阻塞或者执行其他操作时,其他线程同样可以完成操作A,而当线程B恢复执行或者要执行操作A时,因A已被执行,而无需线程B再执行,从而提高了B的执行效率。
Balking模式和Guarded Suspension模式一样,存在守护条件,如果守护条件不满足,则中断处理;这与Guarded Suspension模式不同,Guarded Suspension模式在守护条件不满足的时候会一直等待至可以运行。
使用场景
1、sychronized轻量级锁膨胀逻辑, 只需要一个线程膨胀获取monitor对象。
2、DCL单例实现。
3、服务组件的初始化。
如何实现Balking模式
1、锁机制 (synchronized reentrantLock)
2、cas
3、对于共享变量不要求原子性的场景,可以使用volatile
需要快速放弃的一个最常见的场景是各种编辑器提供的自动保存功能。自动保存功能的实现逻辑一
般都是隔一定时间自动执行存盘操作,存盘操作的前提是文件做过修改,如果文件没有执行过修改操作,就需要快速放弃存盘操作。
多线程分工模式
Thread-Per-Message 模式、Worker Thread 模式和生产者 - 消费者模式属于多线程分工模式。
1、Thread-Per-Message 模式需要注意线程的创建,销毁以及是否会导致OOM。
2、Worker Thread 模式需要注意死锁问题,提交的任务之间不要有依赖性。
3、生产者 - 消费者模式可以直接使用线程池来实现。
Thread-Per-Message 模式——最简单实用的分工方法
Thread-Per-Message 模式就是为每个任务分配一个独立的线程,这是一种最简单的分工方法。
应用场景
Thread-Per-Message 模式的一个最经典的应用场景是网络编程里服务端的实现,服务端为每个客户端请求创建一个独立的线程,当线程处理完请求后,自动销毁,这是一种最简单的并发处理网络请求的方法。
Thread-Per-Message 模式作为一种最简单的分工方案,Java 中使用会存在性能缺陷。在 Java 中的线程是一个重量级的对象,创建成本很高,一方面创建线程比较耗时,另一方面线程占用的内存也比较大。所以为每个请求创建一个新的线程并不适合高并发场景。为了解决这个缺点,Java 并发包里提供了线程池等工具类。
在其他编程语言里,例如 Go 语言,基于轻量级线程实现 Thread-Per-Message 模式就完全没有问题。
对于一些并发度没那么高的异步场景,例如定时任务,采用 Thread-Per-Message 模式是完全没有问题的。
Worker Thread模式——如何避免重复创建线程
要想有效避免线程的频繁创建、销毁以及 OOM 问题,就不得不提 Java 领域使用最多的 WorkerThread 模式。Worker Thread 模式可以类比现实世界里车间的工作模式:车间里的工人,有活儿了,大家一起干,没活儿了就聊聊天等着。Worker Thread 模式中 Worker Thread 对应到现实世界里,其实指的就是车间里的工人。
应用场景
Worker Thread 模式能避免线程频繁创建、销毁的问题,而且能够限制线程的最大数量。Java语言里可以直接使用线程池来实现 Worker Thread 模式,线程池是一个非常基础和优秀的工具类,甚至有些大厂的编码规范都不允许用 new Thread() 来创建线程,必须使用线程池。
生产者 - 消费者模式——用流水线的思想提高效率
Worker Thread 模式类比的是工厂里车间工人的工作模式。但其实在现实世界,工厂里还有一种流水线的工作模式,类比到编程领域,就是生产者 - 消费者模式。
生产者 - 消费者模式的核心是一个任务队列,生产者线程生产任务,并将任务添加到任务队列中,而消费者线程从任务队列中获取任务并执行。
生产者 - 消费者模式的优点
支持异步处理
场景:用户注册后,需要发注册邮件和注册短信。传统的做法有两种 1.串行的方式;2.并行方式
引入消息队列,将不是必须的业务逻辑异步处理。
解耦
场景:用户下单后,订单系统需要通知库存系统扣减库存。
可以消除生产者生产与消费者消费之间速度差异
在计算机当中,创建的线程越多,CPU进行上下文切换的成本就越大,所以我们在编程的时候创建的线程并不是越多越好,而是适量即可,采用生产者和消费者模式就可以很好的支持我们使用适量的线程来完成任务。
如果在某一段业务高峰期的时间里生产者“生产”任务的速率很快,而消费者“消费”任务速率很慢,由于中间的任务队列的存在,也可以起到缓冲的作用,我们在使用MQ中间件的时候,经常说的削峰填谷也就是这个意思。
过饱问题解决方案
在实际生产项目中会有些极端的情况,导致生产者/消费者模式可能出现过饱的问题。单位时间内,生产者生产的速度大于消费者消费的速度,导致任务不断堆积到阻塞队列中,队列堆满只是时间问题。
思考:是不是只要保证消费者的消费速度一直比生产者生产速度快就可以解决过饱问题?
我们只要在业务可以容忍的最长响应时间内,把堆积的任务处理完,那就不算过饱。
什么是业务容忍的最长响应时间?
比如埋点数据统计前一天的数据生成报表,第二天老板要看的,你前一天的数据第二天还没处理完,那就不行,这样的系统我们就要保证,消费者在24小时内的消费能力要比生产者高才行。
场景一:消费者每天能处理的量比生产者生产的少;如生产者每天1万条,消费者每天只能消费5千条。
解决办法:消费者加机器
原因:生产者没法限流,因为要一天内处理完,只能消费者加机器。
场景二:消费者每天能处理的量比生产者生产的多。系统高峰期生产者速度太快,把队列塞爆了
解决办法:适当的加大队列
原因:消费者一天的消费能力已经高于生产者,那说明一天之内肯定能处理完,保证高峰期别把队列塞满就好
场景三:消费者每天能处理的量比生产者生产的多。条件有限或其他原因,队列没法设置特别大。系统高峰期生产者速度太快,把队列塞爆了
解决办法:生产者限流
原因:消费者一天的消费能力高于生产者,说明一天内能处理完,队列又太小,那只能限流生产者,让高峰期塞队列的速度慢点。
相关文章:

常用并发设计模式
避免共享的设计模式 不变性(Immutability)模式,写时复制(Copy-on-Write)模式,线程本地存储(Thread-Specific Storage)模式本质上都是为了避免共享。 1、使用时需要注意不变性模式…...

Redis Search系列 - 第七讲 Windows(CygWin)编译Friso
目录 一、背景二、安装CygWin三、编译Friso四、运行Friso五、Friso分词效果测试 一、背景 最近在做RedisSearch的中文分词效果调研,底层的中文分词插件使用的就是Friso,目前手里的Linux环境上yum镜像仓库有问题导致没法安装gcc,又急于验证Fr…...

利用Docker容器技术部署发布web应用程序
Docker是什么? docker 是一个开源的应用容器引擎,可以帮助开发者打包应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何…...

[免费]SpringBoot+Vue毕业设计论文管理系统【论文+源码+SQL脚本】
大家好,我是java1234_小锋老师,看到一个不错的SpringBootVue毕业设计论文管理系统,分享下哈。 项目视频演示 【免费】SpringBootVue毕业设计论文管理系统 Java毕业设计_哔哩哔哩_bilibili 项目介绍 现代经济快节奏发展以及不断完善升级的信…...

BFS 算法专题(五):BFS 解决拓扑排序
目录 1. 拓扑排序简介 1.1 有向无环图 (DAG 图) 1.2 AOV 网(顶点活动图) 1.3 拓扑排序 1.3.1 如何实现 2. 力扣实战应用 2.1 课程表 2.1.1 算法原理 2.1.2 算法代码 2.2 课程表 II 2.2.1 算法原理 2.2.2 算法代码 2.3 火星词典 (hard) (原剑指offer) 2.3.1 算法原理…...

【Mysql】开窗聚合函数----SUM,AVG, MIN,MAX
1、概念 在窗口中,每条记录动态地应用聚合函数(如:SUM(),AVG(),MAX(),MIN(),COUNT(),)可以动态计算在指定的窗口内的各种聚合函数值。 2、操作 以下操作将基于employee表进行操作。 sum() 进行sum的时候,没有order …...

java操作doc——java利用Aspose.Words操作Word文档并动态设置单元格合并
在实际工作中,如果业务线是管理类项目或者存在大量报表需要导出的业务时,可以借助第三方插件实现其对应功能。 尤其是需要对word文档的动态操作或者模板数据的定向合并,使用Aspose会相对来说容易一些,而且相关文档比较完整&#…...

探索 .NET 9 控制台应用中的 LiteDB 异步 CRUD 操作
本文主要是使用异步方式,体验 litedb 基本的 crud 操作。 LiteDB 是一款轻量级、快速且免费的 .NET NoSQL 嵌入式数据库,专为小型本地应用程序设计。它以单一数据文件的形式提供服务,支持文档存储和查询功能,适用于桌面应用、移动…...

《进程隔离机制:C++多进程编程安全的坚固堡垒》
在当今数字化时代,软件系统的安全性愈发成为人们关注的焦点。尤其是在 C多进程编程领域,如何确保进程间的安全交互与数据保护,是每一位开发者都必须面对的重要课题。而进程隔离机制,犹如一座坚固的堡垒,为 C多进程编程…...

构建无障碍的数字世界:深入探讨Web可访问性指南
文章目录 前言一、什么是Web可访问性?二、Web内容无障碍指南(WCAG)三、ARIA属性的应用四、实践中的Web可访问性结语 前言 在当今高度互联的世界里,互联网已成为人们日常生活不可或缺的一部分。然而,对于数百万残障人士…...

跨境出海安全:如何防止PayPal账户被风控?
今天咱们聊聊那些让人头疼的事儿——PayPal账户被风控。不少跨境电商商家反馈,我们只是想要安安静静地在网上做个小生意,结果不知道为什么,莫名其妙账户就被冻结了。 但其实每个封禁都是有原因的,今天就来给大家分享分享可能的原…...

学习日记_20241123_聚类方法(MeanShift)
前言 提醒: 文章内容为方便作者自己后日复习与查阅而进行的书写与发布,其中引用内容都会使用链接表明出处(如有侵权问题,请及时联系)。 其中内容多为一次书写,缺少检查与订正,如有问题或其他拓展…...

AI编程和AI绘画哪个更适合创业?
AI编程和AI绘画各有优势,适合创业的方向取决于你的资源、兴趣、市场需求和技术能力。以下是两者的对比分析,帮助你选择更适合的方向: AI编程 优势 1、广泛应用领域: 涉及自动化、数据分析、自然语言处理、计算机视觉等多个领域&a…...

macOS 无法安装第三方app,启用任何来源的方法
升级新版本 MacOS 后,安装下载的软件时,不能在 ”安全性与隐私” 中找不到 ”任何来源” 选项。 1. 允许展示任何来源 点击 启动器 (Launchpad) – 其他 (Other) – 终端 (Terminal): 打开终端后,输入以下代码回车: …...

关于SpringBoot集成Kafka
关于Kafka Apache Kafka 是一个分布式流处理平台,广泛用于构建实时数据管道和流应用。它能够处理大量的数据流,具有高吞吐量、可持久化存储、容错性和扩展性等特性。 Kafka一般用作实时数据流处理、消息队列、事件架构驱动等 Kafka的整体架构 ZooKeeper:…...

4.STM32之通信接口《精讲》之IIC通信---软件实现IIC《深入浅出》面试必备!
接下正式,进入软件编写IIC时序了,并实现对MPU6050的控制,既然是软件实现,那么硬件方面,我仅需两根控制线即可,即:数据控制线SDA,时钟控制线SCL。(人为软件层面定义的&…...

6G通信技术对比5G有哪些不同?
6G,即第六代移动通信技术,是5G之后的延伸,代表了一种全新的通信技术发展方向。与5G相比,6G在多个方面都有显著的不同和提升,以下是对6G通信技术及其与5G差异的详细分析: 一、6G的基本特点 更高的传输速率…...

「Mac玩转仓颉内测版28」基础篇8 - 元组类型详解
本篇将介绍 Cangjie 中的元组类型,包括元组的定义、创建、访问、数据解构以及应用场景,帮助开发者掌握元组类型的使用。 关键词 元组类型定义元组创建元组访问数据解构应用场景 一、元组类型概述 在 Cangjie 中,元组是一种用于存储多种数据…...

WebStorm 2024.3/IntelliJ IDEA 2024.3出现elementUI提示未知 HTML 标记、组件引用爆红等问题处理
WebStorm 2024.3/IntelliJ IDEA 2024.3出现elementUI提示未知 HTML 标记、组件引用爆红等问题处理 1. 标题识别elementUI组件爆红 这个原因是: 在官网说明里,才版本2024.1开始,默认启用的 Vue Language Server,但是在 Vue 2 项目…...

机械设计学习资料
免费送大家学习资源,已整理好,仅供学习 下载网址: https://www.zzhlszk.com/?qZ02-%E6%9C%BA%E6%A2%B0%E8%AE%BE%E8%AE%A1%E8%A7%84%E8%8C%83SOP.zip...

Python 快速入门(上篇)❖ Python 字符串
Python 字符串 字符串格式化输出字符串拼接获取字符串长度字符串切片字符串处理方法 字符串格式化输出 name “xhx” age 30 # 方法1 print("我的名字是%s,今年%s岁了。 " % (name, age)) # 方法2 print(f"我的名字是{name},今年{age}岁了。")字符串拼接…...

Ubuntu中使用多版本的GCC
我的系统中已经安装了GCC11.4,在安装cuda时出现以下错误提示: 意思是当前的GCC版本过高,要在保留GCC11.4的同时安装GCC9并可以切换,可以通过以下步骤实现: 步骤 1: 安装 GCC 9 sudo apt-get update sudo apt-get ins…...

1+X应急响应(网络)文件包含漏洞:
常见网络攻击-文件包含漏洞&命令执行漏洞: 文件包含漏洞简介: 分析漏洞产生的原因: 四个函数: 产生漏洞的原因: 漏洞利用条件: 文件包含: 漏洞分类: 本地文件包含: …...

机器学习实战记录(1)
决策树——划分数据集 def splitDataSet(dataSet, axis, value): retDataSet [] #创建返回的数据集列表for featVec in dataSet: #遍历数据集if featVec[axis] value:reducedFeatVec featVec[:axis] #去掉axis特征reducedFeatVec.extend(featVec[axis1…...

PHP8解析php技术10个新特性
PHP8系列是 PHP编程语言的最新主线版本,带来了许多激动人心的新特性和改进。作为一名PHP开发者,了解这些更新能够帮助你编写更高效、安全和现代的代码。 8的核心技术知识点,包括语言特性、性能优化、安全增强以及开发者工具的改进。 Just-In…...

C++模版特化和偏特化
什么是模版特化 特化的含义:所谓特化,就是将泛型搞得具体化一些,从字面上来解释,就是为已有的模板参数进行一些使其特殊化的指定,使得以前不受任何约束的模板参数,或受到特定的修饰(例如const或…...

Simulink中Model模块的模型保护功能
在开发工作过程中,用户为想要知道供应商的开发能力,想要供应商的模型进行测试。面对如此要求,为了能够尽快拿到定点项目,供应商会选择一小块算法或是模型以黑盒的形式供客户测试。Simulink的Model模块除了具有模块引用的功能之外&…...

Linux常用工具的使用(2):文本编辑器的使用
实验题目:Linux常用工具的使用(2):文本编辑器的使用 实验目的: (1)理解文本编辑器vi的工作模式; (2)掌握文本编辑器的使用方法 实验内容: &a…...

【StarRocks】starrocks 3.2.12 【share-nothing】 多Be集群容器化部署
文章目录 一. 集群规划二.docker compose以及启动脚本卷映射对于网络环境变量 三. 集群测试用户新建、赋权、库表初始化断电重启扩容 BE 集群 一. 集群规划 部署文档 https://docs.starrocks.io/zh/docs/2.5/deployment/plan_cluster/ 分类描述FE节点1. 主要负责元数据管理、…...

联想ThinkServer服务器主要硬件驱动下载
联想ThinkServer服务器主要硬件驱动下载: 联想ThinkServer服务器主要硬件Windows Server驱动下载https://newsupport.lenovo.com.cn/commonProblemsDetail.html?noteid156404#D50...