mirror of
https://github.com/Snailclimb/JavaGuide
synced 2025-06-16 18:10:13 +08:00
[docs add]程序人生新增两篇优秀的文章
This commit is contained in:
parent
f601220639
commit
21573992f6
@ -8,6 +8,7 @@ export const highQualityTechnicalArticles = arraySidebar([
|
|||||||
collapsible: false,
|
collapsible: false,
|
||||||
children: [
|
children: [
|
||||||
"the-growth-strategy-of-the-technological-giant",
|
"the-growth-strategy-of-the-technological-giant",
|
||||||
|
"ten-years-of-dachang-growth-road",
|
||||||
"seven-tips-for-becoming-an-advanced-programmer",
|
"seven-tips-for-becoming-an-advanced-programmer",
|
||||||
"20-bad-habits-of-bad-programmers",
|
"20-bad-habits-of-bad-programmers",
|
||||||
],
|
],
|
||||||
@ -38,7 +39,7 @@ export const highQualityTechnicalArticles = arraySidebar([
|
|||||||
text: "面试",
|
text: "面试",
|
||||||
icon: "interview",
|
icon: "interview",
|
||||||
prefix: "interview/",
|
prefix: "interview/",
|
||||||
collapsible: false,
|
collapsible: true,
|
||||||
children: [
|
children: [
|
||||||
"the-experience-of-get-offer-from-over-20-big-companies",
|
"the-experience-of-get-offer-from-over-20-big-companies",
|
||||||
"the-experience-and-thinking-of-an-interview-experienced-by-an-older-programmer",
|
"the-experience-and-thinking-of-an-interview-experienced-by-an-older-programmer",
|
||||||
@ -54,9 +55,10 @@ export const highQualityTechnicalArticles = arraySidebar([
|
|||||||
text: "工作",
|
text: "工作",
|
||||||
icon: "work",
|
icon: "work",
|
||||||
prefix: "work/",
|
prefix: "work/",
|
||||||
collapsible: false,
|
collapsible: true,
|
||||||
children: [
|
children: [
|
||||||
"get-into-work-mode-quickly-when-you-join-a-company",
|
"get-into-work-mode-quickly-when-you-join-a-company",
|
||||||
|
"32-tips-improving-career",
|
||||||
"employee-performance",
|
"employee-performance",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -0,0 +1,134 @@
|
|||||||
|
---
|
||||||
|
title: 十年大厂成长之路
|
||||||
|
category: 技术文章精选集
|
||||||
|
author: CodingBetterLife
|
||||||
|
tag:
|
||||||
|
- 练级攻略
|
||||||
|
---
|
||||||
|
|
||||||
|
> **推荐语**:这篇文章的作者有着丰富的工作经验,曾在大厂工作了 12 年。结合自己走过的弯路和接触过的优秀技术人,他总结出了一些对于个人成长具有普遍指导意义的经验和特质
|
||||||
|
>
|
||||||
|
> **原文地址:** <https://mp.weixin.qq.com/s/vIIRxznpRr5yd6IVyNUW2w>
|
||||||
|
|
||||||
|
最近这段时间,有好几个年轻的同学和我聊到自己的迷茫。其中有关于技术成长的、有关于晋升的、有关于择业的。我很高兴他们愿意听我这个“过来人”分享自己的经验。
|
||||||
|
|
||||||
|
我自己毕业后进入大厂,在大厂工作 12 年,我说的内容都来自于我自己或者身边人的真实情况。尤其,我会把 **【我自己走过的弯路】** 和 **【我看到过的优秀技术人的特质】** 相结合来给出建议。
|
||||||
|
|
||||||
|
这些内容我觉得具有普遍的指导意义,所以决定做个整理分享出来。我相信,无论你在大厂还是小厂,如果你相信这些建议,或早或晚他们会帮助到你。
|
||||||
|
|
||||||
|
我自己工作 12 年,走了些弯路,所以我就来讲讲,“在一个技术人 10 年的发展过程中,应该注意些什么”。我们把内容分为两块:
|
||||||
|
|
||||||
|
1. **十年技术路怎么走**
|
||||||
|
2. **一些重要选择**
|
||||||
|
|
||||||
|
## 01 十年技术路怎么走
|
||||||
|
|
||||||
|
### 【1-2 年】=> 从“菜鸟”到“职业”
|
||||||
|
|
||||||
|
应届生刚进入到工作时,会有各种不适应。比如写好的代码会被反复打回、和团队老司机讨论技术问题会有一堆问号、不敢提问和质疑、碰到问题一个人使劲死磕等等。
|
||||||
|
|
||||||
|
**简单来说就是,即使日以继夜地埋头苦干,最后也无法顺利的开展工作。**
|
||||||
|
|
||||||
|
这个阶段最重要的几个点:
|
||||||
|
|
||||||
|
**【多看多模仿】**:比如写代码的时候,不要就像在学校完成书本作业那样只关心功能是否正确,还要关心模块的设计、异常的处理、代码的可读性等等。在你还没有了解这些内容的精髓之前,也要照猫画虎地模仿起来,慢慢地你就会越来越明白真实世界的代码是怎么写的,以及为什么要这么写。
|
||||||
|
|
||||||
|
做技术方案的时候也是同理,技术文档的要求你也许并不理解,但你可以先参考已有文档写起来。
|
||||||
|
|
||||||
|
**【脸皮厚一点】**:不懂就问,你是新人大家都是理解的。你做的各种方案也可以多找老司机们 review,不要怕被看笑话。
|
||||||
|
|
||||||
|
**【关注工作方式】**:比如发现需求在计划时间完不成就要尽快报风险、及时做好工作内容的汇报(例如周报)、开会后确定会议结论和 todo 项、承诺时间就要尽力完成、严格遵循公司的要求(例如发布规范、权限规范等)
|
||||||
|
|
||||||
|
一般来说,工作 2 年后,你就应该成为一个职业人。老板可以相信任何工作交到你的手里,不会出现“意外”(例如一个重要需求明天要上线了,突然被告知上不了)。
|
||||||
|
|
||||||
|
### 【3-4 年】=> 从“职业”到“尖兵”
|
||||||
|
|
||||||
|
工作两年后,对业务以及现有系统的了解已经到达了一定的程度,技术同学会开始承担更有难度的技术挑战。
|
||||||
|
|
||||||
|
例如需要将性能提升到某一个水位、例如需要对某一个重要模块进行重构、例如有个重要的项目需要协同 N 个团队一起完成。
|
||||||
|
|
||||||
|
可见,上述的这些技术问题,难度都已经远远超过一个普通的需求。解决这些问题需要有一定的技术能力,同时也需要具备更高的协同能力。
|
||||||
|
|
||||||
|
这个阶段最重要的几个点:
|
||||||
|
|
||||||
|
**【技术能力提升】**:无论是公司内还是公司外的技术内容,都要多做主动的学习。基本上这个阶段的技术难题都集中在【性能】【稳定性】和【扩展性】上,而这些内容在业界都是有成型的方法论的。
|
||||||
|
|
||||||
|
**【主人翁精神】**:技术难题除了技术方案设计及落地外,背后还有一系列的其他工作。例如上线后对效果的观测、重点项目对于上下游改造和风险的了解程度、对于整个技改后续的计划(二期、三期的优化思路)等。
|
||||||
|
|
||||||
|
在工作四年后,基本上你成为了团队的一、二号技术位。很多技术难题即使不是你来落地,也是由你来决定方案。你会做调研、会做方案对比、会考虑整个技改的生命周期。
|
||||||
|
|
||||||
|
### 【5-7 年】=> 从“尖兵”到“专家”
|
||||||
|
|
||||||
|
技术尖兵重点在于解决某一个具体的技术难题或者重点项目。而下一步的发展方向,就是能够承担起来一整个“业务板块”,也就是“领域技术专家”。
|
||||||
|
|
||||||
|
想要承担一整个“业务板块”需要 **【对业务领域有深刻的理解,同时基于这些理解来规划技术的发展方向】** 。
|
||||||
|
|
||||||
|
拿支付做个例子。简单的支付功能其实很容易完成,只要处理好和双联(网联和银联)的接口调用(成功、失败、异常)即可。但在很多背景下,支付没有那么简单。
|
||||||
|
|
||||||
|
例如,支付是一个用户敏感型操作,非常强调用户体验,如何能兼顾体验和接口的不稳定?支付接口还需要承担费用,同步和异步的接口费用不同,如何能够降本?支付接口往往还有限额等。这一系列问题的背后涉及到很多技术的设计,包括异步化、补偿设计、资金流设计、最终一致性设计等等。
|
||||||
|
|
||||||
|
这个阶段最重要的几个点:
|
||||||
|
|
||||||
|
**【深入理解行业及趋势】**:密切关注行业的各种变化(新鲜的玩法、政策的变动、竞对的策略、科技等外在因素的影响等等),和业务同学加强沟通。
|
||||||
|
|
||||||
|
**【深入了解行业解决方案】**:充分对标已有的国内外技术方案,做深入学习和尝试,评估建设及运维成本,结合业务趋势制定计划。
|
||||||
|
|
||||||
|
### 【8-10 年】=> 从“专家”到“TL”
|
||||||
|
|
||||||
|
其实很多时候,如果能做到专家,基本也是一个 TL 的角色了,但这并不代表正在执行 TL 的职责。
|
||||||
|
|
||||||
|
专家虽然已经可以做到“为业务发展而规划好技术发展”,但问题是要怎么落地呢?显然,靠一个人的力量是不可能完成建设的。所以,这里的 TL 更多强调的不是“领导”这个职位,而是 **【通过聚合一个团队的力量来实施技术规划】** 。
|
||||||
|
|
||||||
|
所以,这里的 TL 需要具备【团队技术培养】【合理分配资源】【确认工作优先级】【激励与奖惩】等各种能力。
|
||||||
|
|
||||||
|
这个阶段最重要的几个点:
|
||||||
|
|
||||||
|
**【学习管理学】**:这里的管理学当然不是指 PUA,而是指如何在每个同学都有各自诉求的现实背景下,让个人目标和团队目标相结合,产生向前发展的动力。
|
||||||
|
|
||||||
|
**【始终扎根技术】**:很多时候,工作重心偏向管理以后,就会荒废技术。但事实是,一个优秀的领导永远是一个优秀的技术人。参与一起讨论技术方案并给予指导、不断扩展自己的技术宽度、保持对技术的好奇心,这些是让一个技术领导持续拥有向心力的关键。
|
||||||
|
|
||||||
|
## 02 一些重要选择
|
||||||
|
|
||||||
|
下面来聊聊在十年间我们可能会碰到的一些重要选择。这些都是真实的血与泪的教训。
|
||||||
|
|
||||||
|
### 我该不该转岗?
|
||||||
|
|
||||||
|
大厂都有转岗的机制。转岗可以帮助员工寻找自己感兴趣的方向,也可以帮助新型团队招募有即战力的同学。
|
||||||
|
|
||||||
|
转岗看似只是在公司内部变动,但你需要谨慎决定。
|
||||||
|
|
||||||
|
本人转岗过多次。虽然还在同一家公司,但转岗等同于换工作。无论是领域沉淀、工作内容、信任关系、协作关系都是从零开始。
|
||||||
|
|
||||||
|
针对转岗我的建议是:**如果你是想要拓宽自己的技术广度,也就是抱着提升技术能力的想法,我觉得可以转岗。但如果你想要晋升,不建议你转岗。**晋升需要在一个领域的持续积淀和在一个团队信任感的持续建立。
|
||||||
|
|
||||||
|
当然,转岗可能还有其他原因,例如家庭原因、身体原因等,这个不展开讨论了。
|
||||||
|
|
||||||
|
### 我该不该跳槽?
|
||||||
|
|
||||||
|
跳槽和转岗一样,往往有很多因素造成,不能一概而论,我仅以几个场景来说:
|
||||||
|
|
||||||
|
**【晋升失败】**:扪心自问,如果你觉得自己确实还不够格,那你就踏踏实实继续努力。如果你觉得评委有失偏颇,你可以尝试去外面面试一下,让市场来给你答案。
|
||||||
|
|
||||||
|
**【成长局限】**:觉得自己做的事情没有挑战,无法成长。你可以和老板聊一下,有可能是因为你没有看到其中的挑战,也有可能老板没有意识到你的“野心”。
|
||||||
|
|
||||||
|
**【氛围不适】**:一般来自于新入职或者领导更换,这种情况下不适是正常的。我的建议是,**如果一个环境是“对事不对人”的,那就可以留下来**,努力去适应,这种不适应只是做事方式不同导致的。但如果这个环境是“对人不对事”的话,走吧。
|
||||||
|
|
||||||
|
### 跳槽该找怎样的工作?
|
||||||
|
|
||||||
|
我们跳槽的时候往往会同时面试好几家公司。行情好的时候,往往可以收到多家 offer,那么我们要如何选择呢?
|
||||||
|
|
||||||
|
考虑一个 offer 往往有这几点:【公司品牌】【薪资待遇】【职级职称】【技术背景】。每个同学其实都有自己的诉求,所以无论做什么选择都没有对错之分。
|
||||||
|
|
||||||
|
我的一个建议是:**你要关注新岗位的空间,这个空间是有希望满足你的期待的**。
|
||||||
|
|
||||||
|
比如,你想成为架构师,那新岗位是否有足够的技术挑战来帮助你提升技术能力,而不仅仅是疲于奔命地应付需求?
|
||||||
|
|
||||||
|
比如,你想往技术管理发展,那新岗位是否有带人的机会?是否有足够的问题需要搭建团队来解决?
|
||||||
|
|
||||||
|
比如,你想扎根在某个领域持续发展(例如电商、游戏),那新岗位是不是延续这个领域,并且可以碰到更多这个领域的问题?
|
||||||
|
|
||||||
|
当然,如果薪资实在高到无法拒绝,以上参考可以忽略!
|
||||||
|
|
||||||
|
## 结语
|
||||||
|
|
||||||
|
以上就是我对互联网从业技术人员十年成长之路的心得,希望在你困惑和关键选择的时候可以帮助到你。如果我的只言片语能够在未来的某个时间帮助到你哪怕一点,那将是我莫大的荣幸。
|
@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
title: 我的个人校招经历和经验
|
title: 校招进入飞书的个人经验
|
||||||
category: 技术文章精选集
|
category: 技术文章精选集
|
||||||
author: 月色真美
|
author: 月色真美
|
||||||
tag:
|
tag:
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
## 练级攻略
|
## 练级攻略
|
||||||
|
|
||||||
- [程序员的技术成长战略](./advanced-programmer/the-growth-strategy-of-the-technological-giant.md)
|
- [程序员的技术成长战略](./advanced-programmer/the-growth-strategy-of-the-technological-giant.md)
|
||||||
|
- [十年大厂成长之路](./advanced-programmer/ten-years-of-dachang-growth-road.md)
|
||||||
- [给想成长为高级别开发同学的七条建议](./advanced-programmer/seven-tips-for-becoming-an-advanced-programmer.md)
|
- [给想成长为高级别开发同学的七条建议](./advanced-programmer/seven-tips-for-becoming-an-advanced-programmer.md)
|
||||||
- [糟糕程序员的 20 个坏习惯](./advanced-programmer/20-bad-habits-of-bad-programmers.md)
|
- [糟糕程序员的 20 个坏习惯](./advanced-programmer/20-bad-habits-of-bad-programmers.md)
|
||||||
|
|
||||||
@ -40,4 +41,5 @@
|
|||||||
## 工作
|
## 工作
|
||||||
|
|
||||||
- [新入职一家公司如何快速进入工作状态](./work/get-into-work-mode-quickly-when-you-join-a-company.md)
|
- [新入职一家公司如何快速进入工作状态](./work/get-into-work-mode-quickly-when-you-join-a-company.md)
|
||||||
|
- [32条总结教你提升职场经验](./work/32-tips-improving-career.md)
|
||||||
- [聊聊大厂的绩效考核](./work/employee-performance.md)
|
- [聊聊大厂的绩效考核](./work/employee-performance.md)
|
||||||
|
@ -0,0 +1,70 @@
|
|||||||
|
---
|
||||||
|
title: 32条总结教你提升职场经验
|
||||||
|
category: 技术文章精选集
|
||||||
|
tag:
|
||||||
|
- 工作
|
||||||
|
---
|
||||||
|
|
||||||
|
> **推荐语**:阿里开发者的一篇职场经验的分享。
|
||||||
|
>
|
||||||
|
> **原文地址:** <https://mp.weixin.qq.com/s/6BkbGekSRTadm9j7XUL13g>
|
||||||
|
|
||||||
|
## 成长的捷径
|
||||||
|
|
||||||
|
- 入职伊始谦逊的态度是好的,但不要把“我是新人”作为心理安全线;
|
||||||
|
- 写一篇技术博客大概需要两周左右,但可能是最快的成长方式;
|
||||||
|
- 一定要读两本书:金字塔原理、高效能人士的七个习惯(这本书名字像成功学,实际讲的是如何塑造性格);
|
||||||
|
- 多问是什么、为什么,追本溯源把问题解决掉,试图绕过的问题永远会在下个路口等着你;
|
||||||
|
- 不要沉迷于忙碌带来的虚假安全感中,目标的确定和追逐才是最真实的安全;
|
||||||
|
- 不用过于计较一时的得失,在公平的环境中,吃亏是福不是鸡汤;
|
||||||
|
- 思维和技能不要受限于前端、后端、测试等角色,把自己定位成业务域问题的终结者;
|
||||||
|
- 好奇和热爱是成长最大的捷径,长期主义者会认同自己的工作价值,甚至要高于组织当下给的认同(KPI)。
|
||||||
|
|
||||||
|
## 功夫在日常
|
||||||
|
|
||||||
|
- 每行代码要代表自己当下的最高水平,你觉得无所谓的小细节,有可能就是在晋升场上伤害你的暗箭;
|
||||||
|
- 双周报不是工作日志流水账,不要被时间推着走,最起码要知道下次双周报里会有什么(小目标驱动);
|
||||||
|
- 觉得日常都是琐碎工作、不技术、给师兄打杂等,可以尝试对手头事情做一下分类,想象成每个分类都是个小格子,这些格子连起来的终点就是自己的目标,这样每天不再是机械的做需求,而是有规划的填格子、为目标努力,甚至会给自己加需求,因为自己看清楚了要去哪里;
|
||||||
|
- 日常的言行举止是能力的显微镜,大部分人可能意识不到,自己的强大和虚弱是那么的明显,不要无谓的试图掩盖,更不存在蒙混过关。
|
||||||
|
|
||||||
|
> 最后一条大概意思就是有时候我们会在意自己在聚光灯下(述职、晋升、周报、汇报等)的表现,以为大家会根据这个评价自己。实际上日常是怎么完成业务需求、帮助身边同学、创造价值的,才是大家评价自己的依据,而且每个人是什么样的特质,合作过三次的伙伴就可以精准评价,在聚光灯下的表演只能骗自己。
|
||||||
|
|
||||||
|
## 学会被管理
|
||||||
|
|
||||||
|
> 上级、主管是泛指,开发对口的 PD 主管等也在范围内。
|
||||||
|
|
||||||
|
- 不要传播负面情绪,不要总是抱怨;
|
||||||
|
- 对上级不卑不亢更容易获得尊重,但不要当众反驳对方观点,分歧私下沟通;
|
||||||
|
- 好好做向上管理,尤其是对齐预期,沟通绩效出现 Surprise 双方其实都有责任,但倒霉的是自己;
|
||||||
|
- 尽量站在主管角度想问题:
|
||||||
|
|
||||||
|
- - 这样能理解很多过去感觉匪夷所思的决策;
|
||||||
|
- 不要在意谁执行、功劳是谁的等,为团队分忧赢得主管信任的重要性远远高于这些;
|
||||||
|
- 不要把这个原则理解为唯上,这种最让人不齿。
|
||||||
|
|
||||||
|
## 思维转换
|
||||||
|
|
||||||
|
- 定义问题是个高阶能力,尽早形成 发现问题->定义问题->解决问题->消灭问题 的思维闭环;
|
||||||
|
- 定事情价值导向,做事情结果导向,讲事情问题导向;
|
||||||
|
- 讲不清楚,大概率不是因为自己是实干型,而是没想清楚,在晋升场更加明显;
|
||||||
|
- 当一个人擅长解决某一场景的问题的时候,时间越久也许越离不开这个场景(被人贴上一个标签很难,撕掉一个标签更难)。
|
||||||
|
|
||||||
|
## 要栓住情绪
|
||||||
|
|
||||||
|
- 学会控制情绪,没人会认真听一个愤怒的人在说什么;
|
||||||
|
- 再委屈、再愤怒也要保持理智,不要让自己成为需要被哄着的那种人;
|
||||||
|
- 足够自信的人才会坦率的承认自己的问题,很多时候我们被激怒了,只是因为对方指出了自己藏在深处的自卑;
|
||||||
|
- 伤害我们最深的既不是别人的所作所为,也不是自己犯的错误,而是我们对错误的回应。
|
||||||
|
|
||||||
|
## 成为 Leader
|
||||||
|
|
||||||
|
> Manager 有下属,Leader 有追随者,管理者不需要很多,但人人都可以是 Leader。
|
||||||
|
|
||||||
|
- 让你信服、愿意追随的人不是职务上的 Manager,而是在帮助自己的那个人,自己想服众的话道理一样;
|
||||||
|
- 不要轻易对人做负面评价,片面认知下的评价可能不准确,不经意的传播更是会给对方带来极大的困扰;
|
||||||
|
- Leader 如果不认同公司的使命、愿景、价值观,会过的特别痛苦;
|
||||||
|
- 困难时候不要否定自己的队友,多给及时、正向的反馈;
|
||||||
|
- 船长最重要的事情不是造船,而是激发水手对大海的向往;
|
||||||
|
- Leader 的天然职责是让团队活下去,唯一的途径是实现上级、老板、公司经营者的目标,越是艰难的时候越明显;
|
||||||
|
- Leader 的重要职责是识别团队需要被做的事情,并坚定信念,使众人行,越是艰难的时候越要坚定;
|
||||||
|
- Leader 应该让自己遇到的每个人都感觉自己很重要、被需要。
|
@ -12,7 +12,7 @@ head:
|
|||||||
content: Java集合常见知识点和面试题总结,希望对你有帮助!
|
content: Java集合常见知识点和面试题总结,希望对你有帮助!
|
||||||
---
|
---
|
||||||
|
|
||||||
## Map
|
## Map(重要)
|
||||||
|
|
||||||
### HashMap 和 Hashtable 的区别
|
### HashMap 和 Hashtable 的区别
|
||||||
|
|
||||||
@ -63,11 +63,11 @@ head:
|
|||||||
|
|
||||||
如果你看过 `HashSet` 源码的话就应该知道:`HashSet` 底层就是基于 `HashMap` 实现的。(`HashSet` 的源码非常非常少,因为除了 `clone()`、`writeObject()`、`readObject()`是 `HashSet` 自己不得不实现之外,其他方法都是直接调用 `HashMap` 中的方法。
|
如果你看过 `HashSet` 源码的话就应该知道:`HashSet` 底层就是基于 `HashMap` 实现的。(`HashSet` 的源码非常非常少,因为除了 `clone()`、`writeObject()`、`readObject()`是 `HashSet` 自己不得不实现之外,其他方法都是直接调用 `HashMap` 中的方法。
|
||||||
|
|
||||||
| `HashMap` | `HashSet` |
|
| `HashMap` | `HashSet` |
|
||||||
| :------------------------------------: | :----------------------------------------------------------------------------------------------------------------------: |
|
| :------------------------------------: | :----------------------------------------------------------: |
|
||||||
| 实现了 `Map` 接口 | 实现 `Set` 接口 |
|
| 实现了 `Map` 接口 | 实现 `Set` 接口 |
|
||||||
| 存储键值对 | 仅存储对象 |
|
| 存储键值对 | 仅存储对象 |
|
||||||
| 调用 `put()`向 map 中添加元素 | 调用 `add()`方法向 `Set` 中添加元素 |
|
| 调用 `put()`向 map 中添加元素 | 调用 `add()`方法向 `Set` 中添加元素 |
|
||||||
| `HashMap` 使用键(Key)计算 `hashcode` | `HashSet` 使用成员对象来计算 `hashcode` 值,对于两个对象来说 `hashcode` 可能相同,所以`equals()`方法用来判断对象的相等性 |
|
| `HashMap` 使用键(Key)计算 `hashcode` | `HashSet` 使用成员对象来计算 `hashcode` 值,对于两个对象来说 `hashcode` 可能相同,所以`equals()`方法用来判断对象的相等性 |
|
||||||
|
|
||||||
### HashMap 和 TreeMap 区别
|
### HashMap 和 TreeMap 区别
|
||||||
@ -282,11 +282,69 @@ final void treeifyBin(Node<K,V>[] tab, int hash) {
|
|||||||
|
|
||||||
### HashMap 多线程操作导致死循环问题
|
### HashMap 多线程操作导致死循环问题
|
||||||
|
|
||||||
主要原因在于并发下的 Rehash 会造成元素之间会形成一个循环链表。不过,jdk 1.8 后解决了这个问题,但是还是不建议在多线程下使用 HashMap,因为多线程下使用 HashMap 还是会存在其他问题比如数据丢失。并发环境下推荐使用 ConcurrentHashMap 。
|
JDK1.7 及之前版本的 `HashMap` 在多线程环境下扩容操作可能存在死循环问题,这是由于当一个桶位中有多个元素需要进行扩容时,多个线程同时对链表进行操作,头插法可能会导致链表中的节点指向错误的位置,从而形成一个环形链表,进而使得查询元素的操作陷入死循环无法结束。
|
||||||
|
|
||||||
详情请查看:<https://coolshell.cn/articles/9606.html>
|
为了解决这个问题,JDK1.8 版本的 HashMap 采用了尾插法而不是头插法来避免链表倒置,使得插入的节点永远都是放在链表的末尾,避免了链表中的环形结构。但是还是不建议在多线程下使用 `HashMap`,因为多线程下使用 `HashMap` 还是会存在数据覆盖的问题。并发环境下,推荐使用 `ConcurrentHashMap` 。
|
||||||
|
|
||||||
### HashMap 有哪几种常见的遍历方式?
|
一般面试中这样介绍就差不多,不需要记各种细节,个人觉得也没必要记。如果想要详细了解 `HashMap` 扩容导致死循环问题,可以看看耗子叔的这篇文章:[Java HashMap 的死循环](https://coolshell.cn/articles/9606.html)。
|
||||||
|
|
||||||
|
### HashMap 为什么线程不安全?
|
||||||
|
|
||||||
|
JDK1.7 及之前版本,在多线程环境下,`HashMap` 扩容时会造成死循环和数据丢失的问题。
|
||||||
|
|
||||||
|
数据丢失这个在 JDK1.7 和 JDK 1.8 中都存在,这里以 JDK 1.8 为例进行介绍。
|
||||||
|
|
||||||
|
JDK 1.8 后,在 `HashMap` 中,多个键值对可能会被分配到同一个桶(bucket),并以链表或红黑树的形式存储。多个线程对 `HashMap` 的 `put` 操作会导致线程不安全,具体来说会有数据覆盖的风险。
|
||||||
|
|
||||||
|
举个例子:
|
||||||
|
|
||||||
|
- 两个线程 1,2 同时进行 put 操作,并且发生了哈希冲突(hash 函数计算出的插入下标是相同的)。
|
||||||
|
- 不同的线程可能在不同的时间片获得 CPU 执行的机会,当前线程 1 执行完哈希冲突判断后,由于时间片耗尽挂起。线程 2 先完成了插入操作。
|
||||||
|
- 随后,线程 1 获得时间片,由于之前已经进行过 hash 碰撞的判断,所有此时会直接进行插入,这就导致线程 2 插入的数据被线程 1 覆盖了。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public V put(K key, V value) {
|
||||||
|
return putVal(hash(key), key, value, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
|
||||||
|
boolean evict) {
|
||||||
|
// ...
|
||||||
|
// 判断是否出现 hash 碰撞
|
||||||
|
// (n - 1) & hash 确定元素存放在哪个桶中,桶为空,新生成结点放入桶中(此时,这个结点是放在数组中)
|
||||||
|
if ((p = tab[i = (n - 1) & hash]) == null)
|
||||||
|
tab[i] = newNode(hash, key, value, null);
|
||||||
|
// 桶中已经存在元素(处理hash冲突)
|
||||||
|
else {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
还有一种情况是这两个线程同时 `put` 操作导致 `size` 的值不正确,进而导致数据覆盖的问题:
|
||||||
|
|
||||||
|
1. 线程 1 执行 `if(++size > threshold)` 判断时,假设获得 `size` 的值为 10,由于时间片耗尽挂起。
|
||||||
|
2. 线程 2 也执行 `if(++size > threshold)` 判断,获得 `size` 的值也为 10,并将元素插入到该桶位中,并将 `size` 的值更新为 11。
|
||||||
|
3. 随后,线程 1 获得时间片,它也将元素放入桶位中,并将 size 的值更新为 11。
|
||||||
|
4. 线程 1、2 都执行了一次 `put` 操作,但是 `size` 的值只增加了 1,也就导致实际上只有一个元素被添加到了 `HashMap` 中。
|
||||||
|
|
||||||
|
```java
|
||||||
|
public V put(K key, V value) {
|
||||||
|
return putVal(hash(key), key, value, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
|
||||||
|
boolean evict) {
|
||||||
|
// ...
|
||||||
|
// 实际大小大于阈值则扩容
|
||||||
|
if (++size > threshold)
|
||||||
|
resize();
|
||||||
|
// 插入后回调
|
||||||
|
afterNodeInsertion(evict);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### HashMap 常见的遍历方式?
|
||||||
|
|
||||||
[HashMap 的 7 种遍历方式与性能分析!](https://mp.weixin.qq.com/s/zQBN3UvJDhRTKP6SzcZFKw)
|
[HashMap 的 7 种遍历方式与性能分析!](https://mp.weixin.qq.com/s/zQBN3UvJDhRTKP6SzcZFKw)
|
||||||
|
|
||||||
|
@ -361,6 +361,11 @@ JDK1.2 以后,Java 对引用的概念进行了扩充,将引用分为强引
|
|||||||
|
|
||||||
虽然我们对各个收集器进行比较,但并非要挑选出一个最好的收集器。因为直到现在为止还没有最好的垃圾收集器出现,更加没有万能的垃圾收集器,**我们能做的就是根据具体应用场景选择适合自己的垃圾收集器**。试想一下:如果有一种四海之内、任何场景下都适用的完美收集器存在,那么我们的 HotSpot 虚拟机就不会实现那么多不同的垃圾收集器了。
|
虽然我们对各个收集器进行比较,但并非要挑选出一个最好的收集器。因为直到现在为止还没有最好的垃圾收集器出现,更加没有万能的垃圾收集器,**我们能做的就是根据具体应用场景选择适合自己的垃圾收集器**。试想一下:如果有一种四海之内、任何场景下都适用的完美收集器存在,那么我们的 HotSpot 虚拟机就不会实现那么多不同的垃圾收集器了。
|
||||||
|
|
||||||
|
JDK 默认垃圾收集器(使用 `java -XX:+PrintCommandLineFlags -version` 命令查看):
|
||||||
|
|
||||||
|
- JDK 8:Parallel Scavenge(新生代)+ Parallel Old(老年代)
|
||||||
|
- JDK 9 ~ JDK20: G1
|
||||||
|
|
||||||
### Serial 收集器
|
### Serial 收集器
|
||||||
|
|
||||||
Serial(串行)收集器是最基本、历史最悠久的垃圾收集器了。大家看名字就知道这个收集器是一个单线程收集器了。它的 **“单线程”** 的意义不仅仅意味着它只会使用一条垃圾收集线程去完成垃圾收集工作,更重要的是它在进行垃圾收集工作的时候必须暂停其他所有的工作线程( **"Stop The World"** ),直到它收集结束。
|
Serial(串行)收集器是最基本、历史最悠久的垃圾收集器了。大家看名字就知道这个收集器是一个单线程收集器了。它的 **“单线程”** 的意义不仅仅意味着它只会使用一条垃圾收集线程去完成垃圾收集工作,更重要的是它在进行垃圾收集工作的时候必须暂停其他所有的工作线程( **"Stop The World"** ),直到它收集结束。
|
||||||
@ -477,6 +482,8 @@ G1 收集器的运作大致分为以下几个步骤:
|
|||||||
|
|
||||||
**G1 收集器在后台维护了一个优先列表,每次根据允许的收集时间,优先选择回收价值最大的 Region(这也就是它的名字 Garbage-First 的由来)** 。这种使用 Region 划分内存空间以及有优先级的区域回收方式,保证了 G1 收集器在有限时间内可以尽可能高的收集效率(把内存化整为零)。
|
**G1 收集器在后台维护了一个优先列表,每次根据允许的收集时间,优先选择回收价值最大的 Region(这也就是它的名字 Garbage-First 的由来)** 。这种使用 Region 划分内存空间以及有优先级的区域回收方式,保证了 G1 收集器在有限时间内可以尽可能高的收集效率(把内存化整为零)。
|
||||||
|
|
||||||
|
**从 JDK9 开始,G1 垃圾收集器成为了默认的垃圾收集器。**
|
||||||
|
|
||||||
### ZGC 收集器
|
### ZGC 收集器
|
||||||
|
|
||||||
与 CMS 中的 ParNew 和 G1 类似,ZGC 也采用标记-复制算法,不过 ZGC 对该算法做了重大改进。
|
与 CMS 中的 ParNew 和 G1 类似,ZGC 也采用标记-复制算法,不过 ZGC 对该算法做了重大改进。
|
||||||
|
Loading…
x
Reference in New Issue
Block a user