文章内容输出来源:拉钩教育Java工程师高薪训练营
了解详情传送门:https://kaiwu.lagou.com/java_architect.html?utm_source=app_edu
先容我唠叨几句。岁月不居,时节如流。身处技术行业,学习当然是不能停止的。但愿那些所谓的三四十岁的焦虑不会发生在你的身上。我希望优秀的你看到这篇文章能够获得一些启发。祝早日在自己的领域有所作为。
学习最重要的是掌握方法。不要被哪些让人眼花缭乱的Java学习路线影响到你的情绪。学习要讲究先学脉络再逐个技术点击破。先根据自己的知识水平整理一份学习计划,按部就班的学习就可以了。学习过程中一定要注重输出哦。 个人学习难免受阻于懒惰、不成体系的知识点和难以阅读的源码。当然我也有这些困扰,所以我选择了报班学习投资自己。市面上的学习课程还是很多的,我相信是各有各的好,我并没有全部了解和对比,重要的是学到了才是真的好。我选择了拉钩教育,是因为拉勾本身就是从事互联网招聘,涨薪协议和背书内推使课程内容更加的可靠。有求必应的讲师、班班和导师以及热心的同学们,无疑都是我前进路上的助力剂。我的学习进度已经过半了,已经熟练掌握了各种开源框架的底层原理,理解了分布式理论和架构设计。
以下是教学的整套大纲,非常的体系化,我列在这里也是准备,逐步分文章输出到博客,是为了自己加深了解,也便于大家学习。每模块的内容也是很多的,想要真正吃透是需要下很大功夫的,默默努力吧。
该阶段是通过纯手写持久层、IoC&AOP等框架来培养框架思维和自定义框架的能力,通过SSM源码剖析进一步理解设计模式的具体应用。
模块一 持久层框架设计实现及MyBatis源码分析
通过持久层框架的衍生分析,推导出开发步骤进而纯手写持久层框架,对MyBatis技术系统复习后进行源码剖析。
模块二 IoC容器设计实现及Spring源码分析
从分析代码耦合到IoC思想演进,从功能代码抽取到面向切面AOP思想演进,最后会手写Spring和对Spring进行源码深入分析。
模块三 MVC框架设计实现及SpringMVC源码分析、通用数据操作接口设计及SpringData 接口规范
本模块从MVC设计模式及前端控制器模型分析,手写属于自己的MVC框架,并对SpringMVC源码分析;对Spring Data 接口规范进行深入剖析。
模块四 约定优于配置设计范式及Spring Boot源码剖析
本模块将会剖析约定优于配置设计范式,并分析SpringBoot自动装配实现原理,并对SpringBoot源码进行剖析,探秘底层实现原理及框架设计思想。
该阶段是对Web应用服务器进行深入使用,对Tomcat、Nginx性能调优进行讲解,以及Cluster模式潜在问题及解决方案深入讲解。
模块一 Tomcat深度剖析及性能调优、Nginx深度剖析及性能调优
本模块会对Tomcat工作原理及架构进行剖析、性能调优,分析Tomcat漏洞防护与安全加固策略,及Nginx进程模型及产线配置学习。
模块二 Cluster模式潜在问题及解决方案、Web服务综合解决方案
本模块会对集群状态下一致性Hash和Session共享提出解决方案,并对页面动态模块化渲染、CDN等加以说明。
该阶段为分布式学习提供理论基础,如分布式一致性协议Paxos、远程过程调用RPC等,并对分布式中间件Dubbo和SpringCloud进行深入剖析。
模块一 分布式理论、架构设计(自定义RPC)
本模块会对分布式架构的理论、架构设计、网络通信等进行讲解,并设计一个RPC远程过程调用框架并进行代码编写。
模块二 分布式服务治理、分布式协调服务Zookeeper深入
本模块会对分布式治理中遇到的问题,例如权重、降级、容错路由等进行讲解,并对分布式协调服务Zookeeper进行系统的说明。
模块三 高性能RPC框架Apache Dubbo
本模块对Apache的Dubbo框架进行深入讲解,涉及架构设计、SPI机制、高级使用及其源码分析等内容
模块四 SpringCloud组件设计原理及实战(上)
本模块对SpringCloud的一些高级特性,例如链路追踪设计原理及Sleuth+Zipkin、Spring Cloud Alibaba等进行讲解。
模块五 SpringCloud组件设计原理及实战(下)
本模块对SpringCloud的一些高级特性,例如链路追踪设计原理及Sleuth+Zipkin、Spring Cloud Alibaba等进行讲解。
数据存储瓶颈是架构师重要技能之一,该阶段是对市场上分布式存储进行深入剖析,有分布式数据存储MySQL,分布式文件存储DFS系列,分布式云存储OSS等。
模块一 MySQL海量数据存储与优化(上)
本模块对MySQL体系架构、运行机制、存储引擎、索引原理、事务和锁以及集群架构设计等方面的内容进行深入系统的介绍,并对SQL和架构进行分析及提出性能优化方案。
模块二 MySQL海量数据存储与优化(下)
本模块主要对MySQL海量数据处理中的分库分表架构、ShardingSphere、MyCat中间件实战应用、数据库实战规范、以及一些运维分析工具等内容进行讲解。
模块三 分布式文档存储独角兽MongoDB、知识图谱存储数据库Neo4j
本模块对MongoDB的存储原理以及replica sets & Sharded Cluster等、对Neo4j数据模型及图形理论等进行深入讲解。
模块四 轻量级分布式文件系统FastDFS、阿里云OSS云存储平台
本模块对分布式文件系统FastDFS集群架构与原理剖析,使用FastDFS+Nginx搭建高吞吐文件服务器,并对阿里云OSS云存储平台系统讲解。
模块五 Hadoop分布式文件系统HDFS、海量列式存储数据库HBase
本模块对大数据的基石HDFS进行系统讲解,对HBase 性能提升策略与读写速率优化提出解决方案。
大型互联网项目必备分布式缓存,该阶段对市场上主流的及有一定潜力的缓存服务中间件进行重点讲解,最终可以达到根据不同业务进行分布式缓存选型的能力。
模块一 高性能分布式缓存Redis、分布式 Redis 解决方案Codis(Twemproxy替代方案)
本模块对Redis的持久化方案、删除策略、IO多路复用模型、Redis集群模式、预热、雪崩、击穿、穿透等进行系统剖析。
模块二 Guava Cache、EVCache、Tair、Aerospike
本模块对市场上其他缓存服务进行讲解,例如:Guava Cache、EVCache、Tair、Aerospike等,可以提高在缓存方面的架构选型能力。
该阶段是对高效可靠的消息传递机制进行理论讲解,并对市场上常用的中间件进行讲解,并结合业务场景,完成服务解耦、削峰填谷、分布式事务等实际场景应用。
模块一 Apache开源消息中间件RabbitMQ、RocketMQ
本模块对市场上常用的开源消息中间件RabbitMQ、RocketMQ进行深度剖析、并对ACK、限流、TTL、死信、延迟等高级应用进行讲解。
模块二 高吞吐消息中间件Kafka
本模块对Kafka集群原理和消息流处理流程、组件机制、流处理基础等进行深入讲解,对从架构选型角度对三种MQ进行比较。
该阶段通过检索工具包Lucene对进行分词、倒排索引等概念进行理论讲解,并使用Elasticsearch对拉勾亿级数据进行搜索,使你成为搜索专家。
模块一 引擎工具包Lucene、搜索应用服务器Solr
本模块将对Lucene倒排索引机制和底层存储结构深入讲解、对搜索服务引擎Solr高级特性进行剖析,并使用SolrCloud+Zookeeper进行集群化管理。
模块二 海量日志分析平台Elastic Stack
本模块将针对Elasticsearch的数据模型分析、构建和算法扩展进行深入讲解,结合拉勾网亿级数据量进行搜索实战,最后对es进行性能调优。
通过该阶段学习,我们可以掌握在实际的生产过程中有大量的数据实时性分析需求,例如实时推荐,异常告警,传感器信令分析等需求。
模块一 分布式实时流式计算引擎Flink
本模块对实时流式计算引擎Flink的Flink流处理特性、Flink编程模型及实践进行讲解,并介绍基于Flink的物联网数据实时监控系统。
通过该阶段学习,我们可以使用Docker&K8s打包应用以及依赖包到一个轻量级容器中,方便移植,该阶段还包括其他一系列运维工具的学习。
模块一 容器虚拟化技术、CI/CD、DevOps、服务质量治理
本模块主要深入讲解容器引擎Docker & K8s容器编排系统,对续集成工具Jenkins、代码质量管理工具Sonar、APM管理工具Skywalking等进行讲解。
底层调优和算法是架构师必备技能之一,有时项目性能瓶颈是要通过底层调优实现的,而一些高级的内核和引擎开发往往是需要一些精良算法才能完成的。
模块一 数据结构、算法
本模块会讲解算法高级内容,例如高级数据结构、排序、递归与回溯、深度与广度优先搜索、动态规划、二分搜索与贪婪算法等。
模块二 并发编程、JVM优化、Linux优化
本模块会深入讲解线程高级部分,例如线程状态机制分析与线程池实现原理、抽象队列化同步器AQS等,还会深入JVM分析与调优,Linux性能监控与调优。
该阶段会结合真实的大型互联网项目,将前10个阶段学到的内容与该实际业务相结合,根据实际业务进行架构选型,技术选型等。
模块一 大型互联网项目实战
本模块会以真实开发流程,从需求分析、概要设计、详细设计、编码、测试、上线等几个环节对大型互联网项目进行讲解,夯实之前所学技术。
模块二 主流业务解决方案
本模块是对互联网公司常用的一些解决方案进行讲解,例如:秒杀、SSO、IM、Security、LBS、推送、三方支付等进行拓展讲解。
该阶段会从专项能力突击、如何打造一份让人无法拒绝的简历、如何在面试中发挥应有的实力三部分进行剖析。
模块一 进大厂必备-面试求职深度辅导
本模块会教你怎么编写一份优秀的简历,怎样应对面试,也会有模拟面试环节,让你跟大厂技术面试官有提前训练的机会。
日复一日的搬砖工作,永远不会领略到技术的魅力。新的技术层出不叠,那么我们应如何成长呢。不论你是刚毕业还是转行,基础知识的掌握会使你走的更远。大厂的面试更是离不开这些,正所谓根深才能枝茂。主要包括这几部分内容:并发编程和锁的原理、JVM垃圾回收机制和调优、数据结构和算法。这些内容我会找时间在博客做输出,便于相互探讨学习。
理解了这些底层基础知识才会使你开发的代码效率更加高效,所以掌握这些你就是码农里最亮的仔!下面就是框架部分了。掌握好各种框架的底层原理和应用场景,会使你更好的理解每个技术框架的特点,也会培养你的架构思维,在面对一个新项目时,你会需要这些知识储备做好技术选型。下面就盗用两张图片来看下职业路径规划,共勉。希望你早日找到目标并默默努力。旁观者的名字永远不会挂到计分板上,行动起来吧!!
最烦码字了,说得太多了,都是一些鸡汤。各位同道们加油吧。下面来一点干货吧。不讨论技术的博客都是耍流氓 。
synchronized在JDK1.2之前是重量级锁。后面逐步优化,直到JDK1.6已经优化为下面讲解的情况了。
Compare And Swap (Compare And Exchange) / 自旋锁 / 轻量级锁
自旋理解:一个线程先读取到值A,然后修改为V,更新之前再读取一遍,判断和第一次读取到的A是否一致,从而判断是否有其他线程修改过。如果一直不一致,就要不断循环这个过程。
轻量级理解:这里又会涉及到操作系统的知识。可以理解为加锁过程不经过OS操作系统。
CAS的缺点:
1、循环时间长开销很大耗费CPU。(这个很好理解,因为每次对比发现不一致,当前线程要一直循环)
2、只能保证一个共享变量的原子操作。(这个涉及计算机理论基础,本篇博客先不做解释)
3、ABA问题。(在图示第3步,尽管在比较值的时候是一样的,但其实在当前线程第一次读取到值之后第二次读取对比之前,可能已经被其他线程修改成其他值又修改回原值。)
import java.util.Arrays;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
public class Test02_AtomicInteger {
private static AtomicInteger atomicInteger = new AtomicInteger(0);
public static void main(String[] args) throws InterruptedException {
// 创建了100个线程数组
Thread[] threads = new Thread[100];
// 计数器,为了阻塞主线程等待所有线程执行完毕。
// await方法会阻塞当前线程,直到计数器变为0。每调用一次countDown方法,计数器会减1
CountDownLatch countDownLatch = new CountDownLatch(threads.length);
// 创建了100个线程,每个线程分别对atomicInteger子增加1,循环10000次
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(() -> {
for (int j = 0; j < 10000; j++) {
//自增+1
atomicInteger.incrementAndGet();
}
countDownLatch.countDown();
});
}
// 开始执行线程
Arrays.stream(threads).forEach(thread -> thread.start());
// 阻塞当前线程
countDownLatch.await();
// 输出最后atomicInteger的值,预期是100,0000
System.out.println(atomicInteger);
}
}
我们来跟踪下atomicInteger.incrementAndGet();
这里得compareAndSwapInt就是CAS操作,可以看到是native修饰的方法,底层实现是C++,别急依然可以追踪
所以最终调用的指令就是:lock cmpxchg(cmpxchg=cas修改变量的值)
cmpxchg是CPU的指令,这个指令也是和前面讲的一样,修改前要比较值。涉及到计算机的理论基础,有两颗CPU,其中一颗通过cmpxchg指令要去内存里修改一个值,这个过程是会被另一个CPU打断的,所以就无法保证CAS操作的原子性。所以多核CPU要加lock指令,简单理解就是锁总线(CPU是通过主板上的一组线访问内存,锁住禁止其他CPU访问)。
好啦,以上就是CAS实现源码追踪的过程,简单链路如下:
AtomicInteger.incrementAndGet() --> Unsafe.GetAndAddInt() --> Unsafe.compareAndSwapInt() --> lock cmpxchg(锁总线)
(new 对象)无锁 -> 偏向锁 -> 轻量级锁 (自旋锁)-> 重量级锁
无锁 -> 偏向锁:如果有线程上锁 ,上偏向锁,指的就是,把markword的线程ID改为自己线程ID的过程 。
默认情况,偏向锁有个时延,默认是4秒。为什么呢?因为JVM虚拟机自己有一些默认启动的线程,里面有好多sync代码,这些sync代码启动时就知道肯定会有竞争,如果使用偏向锁,就会造成偏向锁不断的进行锁撤销和锁升级的操作,效率较低。
偏向锁 -> 轻量级锁:如果有线程竞争,撤销偏向锁,升级轻量级锁。线程在自己的线程栈生成LockRecord ,用CAS操作将markword设置为指向自己这个线程的LR的指针,设置成功者得到锁。
轻量级锁 -> 重量级锁:1、竞争加剧(有线程超过10次自旋)。2、自旋线程数超过CPU核数的一半。(1.6之后,加入自适应自旋 Adapative Self Spinning,JVM自己控制升级重量级锁。)
重量级锁,线程挂起,进入等待队列,等待操作系统的调度,不消耗CPU资源。
通过JOL(Java Object Layout)工具查看对象内存布局。
import org.openjdk.jol.info.ClassLayout;
public class Test01_HelloJOL {
public static void main(String[] args) throws InterruptedException {
// Thread.sleep(5000);
Object o = new Object();
System.out.println(ClassLayout.parseInstance(o).toPrintable());
synchronized (o) {
System.out.println(ClassLayout.parseInstance(o).toPrintable());
}
}
}
我来运行展示一下:
可以观察到Object o = new Object();直接打印后三位是001,无锁态。
加了synchronized之后,后三位是000,轻量级锁。
在线程睡了5s后,后三位是101,偏向锁。
自旋锁什么时候升级为重量级锁? 为什么有自旋锁还需要重量级锁? 偏向锁是否一定比自旋锁效率高? 我相信你已经懂了吧。
sychronized是可重入锁,重入次数必须记录,因为要解锁几次必须得对应 。
为什么是可重入锁呢?因为继承,父类方法被sychronized修饰,子类在方法中调用super.该方法,所以可以上两边锁,锁重入。
public void add(String str1,String str2){
StringBuffer sb = new StringBuffer();
sb.append(str1).append(str2);
}
我们都知道 StringBuffer 是线程安全的,因为它的关键方法都是被 synchronized 修饰过的,但我们看上面这段代码,我们会发现,sb 这个引用只会在 add 方法中使用,不可能被其它线程引用(因为是局部变量,栈私有),因此 sb 是不可能共享的资源,JVM 会自动消除 StringBuffer 对象内部的锁。
public String test(String str){
int i = 0;
StringBuffer sb = new StringBuffer():
while(i < 100){
sb.append(str);
i++;
}
return sb.toString():
}
JVM 会检测到这样一连串的操作都对同一个对象加锁(while 循环内 100 次执行 append,没有锁粗化的就要进行 100 次加锁/解锁),此时 JVM 就会将加锁的范围粗化到这一连串的操作的外部(比如 while 虚幻体外),使得这一连串操作只需要加一次锁即可。
OK了,就先讲这些吧,希望你已经对锁的原理有个深刻的了解。