多线程技术的使用一定程度提升了服务器的并发能力,但同时,多个线程之间为了数据同步,常常需要使用互斥体、信号、条件变量等手段来同步多个线程。这些重量级的同步手段往往会导致线程在用户态/内核态多次切换,系统调用,线程切换都是不小的开销。
在线程池技术中,提到了一个公共的任务队列,各个工作线程需要从中提取任务进行处理,这里就涉及到多个工作线程对这个公共队列的同步操作。
有没有一些轻量级的方案来实现多线程安全的访问数据呢?这个时候,你需要:
无锁编程技术
多线程并发编程中,遇到公共数据时就需要进行线程同步。而这里的同步又可以分为阻塞型同步和非阻塞型同步。
阻塞型同步好理解,我们常用的互斥体、信号、条件变量等这些操作系统提供的机制都属于阻塞型同步,其本质都是要加“锁”。
与之对应的非阻塞型同步就是在无锁的情况下实现同步,目前有三类技术方案:
- Wait-free
- Lock-free
- Obstruction-free
三类技术方案都是通过一定的算法和技术手段来实现不用阻塞等待而实现同步,这其中又以Lock-free最为应用广泛。
Lock-free能够广泛应用得益于目前主流的CPU都提供了原子级别的read-modify-write原语,这就是著名的CAS(Compare-And-Swap)操作。在Intel x86系列处理器上,就是cmpxchg系列指令。
// 通过CAS操作实现Lock-free
do {
…
} while(!CAS(ptr,old_data,new_data ))
我们常常见到的无锁队列、无锁链表、无锁HashMap等数据结构,其无锁的核心大都来源于此。在日常开发中,恰当的运用无锁化编程技术,可以有效地降低多线程阻塞和切换带来的额外开销,提升性能。
服务器上线了一段时间,发现服务经常崩溃异常,排查发现是工作线程代码bug,一崩溃整个服务都不可用了。于是你决定把工作线程和主线程拆开到不同的进程中,工作线程崩溃不能影响整体的服务。这个时候出现了多进程,你需要:
进程间通信技术
提起进程间通信,你能想到的是什么?
- 管道
- 命名管道
- socket
- 消息队列
- 信号
- 信号量
- 共享内存
以上各种进程间通信的方式详细介绍和比较,推荐一篇文章一文掌握进程间通信,这里不再赘述。
对于本地进程间需要高频次的大量数据交互,首推共享内存这种方案。
现代操作系统普遍采用了基于虚拟内存的管理方案,在这种内存管理方式之下,各个进程之间进行了强制隔离。程序代码中使用的内存地址均是一个虚拟地址,由操作系统的内存管理算法提前分配映射到对应的物理内存页面,CPU在执行代码指令时,对访问到的内存地址再进行实时的转换翻译。
从上图可以看出,不同进程之中,虽然是同一个内存地址,最终在操作系统和CPU的配合下,实际存储数据的内存页面却是不同的。
而共享内存这种进程间通信方案的核心在于:如果让同一个物理内存页面映射到两个进程地址空间中,双方不是就可以直接读写,而无需拷贝了吗?
当然,共享内存只是最终的数据传输载体,双方要实现通信还得借助信号、信号量等其他通知机制。
用上了高性能的共享内存通信机制,多个服务进程之间就可以愉快的工作了,即便有工作进程出现Crash,整个服务也不至于瘫痪。
不久,老板增加需求了,不再满足于只能提供静态网页浏览了,需要能够实现动态交互。这一次老板还算良心,给你加了一台硬件服务器。
于是你用Java/PHP/Python等语言搞了一套web开发框架,单独起了一个服务,用来提供动态网页支持,和原来等静态内容服务器配合工作。
这个时候你发现,静态服务和动态服务之间经常需要通信。
一开始你用基于HTTP的RESTful接口在服务器之间通信,后来发现用JSON格式传输数据效率低下,你需要更高效的通信方案。
这个时候你需要:
RPC && 序列化技术
什么是RPC技术?
RPC全称Remote Procedure Call,远程过程调用。我们平时编程中,随时都在调用函数,这些函数基本上都位于本地,也就是当前进程某一个位置的代码块。但如果要调用的函数不在本地,而在网络上的某个服务器上呢?这就是远程过程调用的来源。
从图中可以看出,通过网络进行功能调用,涉及参数的打包解包、网络的传输、结果的打包解包等工作。而其中对数据进行打包和解包就需要依赖序列化技术来完成。
什么是序列化技术?
序列化简单来说,是将内存中的对象转换成可以传输和存储的数据,而这个过程的逆向操作就是反序列化。序列化 && 反序列化技术可以实现将内存对象在本地和远程计算机上搬运。好比把大象关进冰箱门分三步:
- 将本地内存对象编码成数据流
- 通过网络传输上述数据流
- 将收到的数据流在内存中构建出对象
序列化技术有很多免费开源的框架,衡量一个序列化框架的指标有这么几个:
- 是否支持跨语言使用,能支持哪些语言
- 是否只是单纯的序列化功能,包不包含RPC框架
- 序列化传输性能
- 扩展支持能力(数据对象增删字段后,前后的兼容性)
- 是否支持动态解析(动态解析是指不需要提前编译,根据拿到的数据格式定义文件立即就能解析)
下面流行的三大序列化框架protobuf、thrift、avro的对比:
ProtoBuf:
厂商
:Google
支持语言
:C++、Java、Python等
动态性支持
:较差,一般需要提前编译
是否包含RPC
:否
简介
:ProtoBuf是谷歌出品的序列化框架,成熟稳定,性能强劲,很多大厂都在使用。自身只是一个序列化框架,不包含RPC功能,不过可以与同是Google出品的GPRC框架一起配套使用,作为后端RPC服务开发的黄金搭档。
缺点是对动态性支持较弱,不过在更新版本中这一现象有待改善。总体来说,ProtoBuf都是一款非常值得推荐的序列化框架。
Thrift
厂商
:Facebook
支持语言
:C++、Java、Python、PHP、C#、Go、JavaScript等
动态性支持
:差
是否包含RPC
:是
简介
:这是一个由Facebook出品的RPC框架,本身内含二进制序列化方案,但Thrift本身的RPC和数据序列化是解耦的,你甚至可以选择XML、JSON等自定义的数据格式。在国内同样有一批大厂在使用,性能方面和ProtoBuf不分伯仲。缺点和ProtoBuf一样,对动态解析的支持不太友好。
Avro
支持语言
:C、C++、Java、Python、C#等
动态性支持
:好
是否包含RPC
:是
简介
:这是一个源自于Hadoop生态中的序列化框架,自带RPC框架,也可独立使用。相比前两位最大的优势就是支持动态数据解析。
为什么我一直在说这个动态解析功能呢?在之前的一段项目经历中,轩辕就遇到了三种技术的选型,摆在我们面前的就是这三种方案。需要一个C++开发的服务和一个Java开发的服务能够进行RPC。
Protobuf和Thrift都需要通过“编译”将对应的数据协议定义文件编译成对应的C++/Java源代码,然后合入项目中一起编译,从而进行解析。
当时,Java项目组同学非常强硬的拒绝了这一做法,其理由是这样编译出来的强业务型代码融入他们的业务无关的框架服务,而业务是常变的,这样做不够优雅。
最后,经过测试,最终选择了AVRO作为我们的方案。Java一侧只需要动态加载对应的数据格式文件,就能对拿到的数据进行解析,并且性能上还不错。(当然,对于C++一侧还是选择了提前编译的做法)
自从你的网站支持了动态能力,免不了要和数据库打交道,但随着用户的增长,你发现数据库的查询速度越来越慢。
这个时候,你需要:
数据库索引技术
想想你手上有一本数学教材,但是目录被人给撕掉了,现在要你翻到讲三角函数的那一页,你该怎么办?
没有了目录,你只有两种办法,要么一页一页的翻,要么随机翻,直到找到三角函数的那一页。
对于数据库也是一样的道理,如果我们的数据表没有“目录”,那要查询满足条件的记录行,就得全表扫描,那可就恼火了。所以为了加快查询速度,得给数据表也设置目录,在数据库领域中,这就是索引。
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
最后如何让自己一步步成为技术专家
说句实话,如果一个打工人不想提升自己,那便没有工作的意义,毕竟大家也没有到养老的年龄。
当你的技术在一步步贴近阿里p7水平的时候,毫无疑问你的薪资肯定会涨,同时你能学到更多更深的技术,交结到更厉害的大牛。
推荐一份Java架构之路必备的学习笔记,内容相当全面!!!
成年人的世界没有容易二字,前段时间刷抖音看到一个程序员连着加班两星期到半夜2点的视频。在这个行业若想要拿高薪除了提高硬实力别无他法。
你知道吗?现在有的应届生实习薪资都已经赶超开发5年的程序员了,实习薪资26K,30K,你没有紧迫感吗?做了这么多年还不如一个应届生,真的非常尴尬!
进了这个行业就不要把没时间学习当借口,这个行业就是要不断学习,不然就只能被裁员。所以,抓紧时间投资自己,多学点技术,眼前困难,往后轻松!
【关注】+【转发】+【点赞】支持我!创作不易!
一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!
AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算
!
进了这个行业就不要把没时间学习当借口,这个行业就是要不断学习,不然就只能被裁员。所以,抓紧时间投资自己,多学点技术,眼前困难,往后轻松!
【关注】+【转发】+【点赞】支持我!创作不易!
一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!
AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算