139
2018 这一年.md
Normal file
@ -0,0 +1,139 @@
|
||||
作者:CyC2018
|
||||
|
||||
链接:https://www.nowcoder.com/discuss/137593
|
||||
|
||||
来源:牛客网
|
||||
|
||||
## 前言
|
||||
|
||||
2018,有过迷茫,有过努力,也有很多收获。为了记录这一年以来的感受,于是有了这篇文章。
|
||||
|
||||
## Offer 情况
|
||||
|
||||
经过了长达一年左右的复习,秋招也收到了几个比较满意的 Offer,参加面试的都通过了。
|
||||
|
||||
- 百度,企业智能平台;
|
||||
- 阿里,高德地图,部门已联系,目前还在申报 Offer 中;
|
||||
- 腾讯,IEG 游戏平台,后台研发,SP;
|
||||
- 字节跳动,头条后台研发,SSP;
|
||||
- 华为,Cloud Bu;
|
||||
- 网易游戏,梦幻事业部;
|
||||
- 顺丰科技。
|
||||
|
||||
## 前期准备
|
||||
|
||||
也是在去年十一月份左右,看着身边两年制的同学经历了长时间而又艰难的秋招,我开始意识到自己应该提前准备了,否则自己的秋招会很惨。
|
||||
|
||||
本科的时候,虽然学过计算机网络、操作系统和数据结构等课程,而且 Leetcode 也刷了一两百题,但是离招聘要求还差的很远,学的都很浅只够应付考试,也没有实际的项目经验。
|
||||
|
||||
我的研究生方向是计算机图形学,研究生期间主要做一些科研项目。在选择招聘方向的时候,我也纠结了是不是找图形学相关方向的,但是考虑到图形学的选择不是很多,所以还是决定投后台研发相关的岗位。
|
||||
|
||||
于是开始收集各种学习资料,也买了很多纸质书。最开始的学习效率并不是很高,很迷茫,觉得要学的内容很多无从下手。那时候看别人的面经,感觉自己太弱了,很多内容都没接触过,于是更加迷茫。迷茫的时候总想着逃避,要是不复习多好,玩玩游戏每天多简单。但是游戏玩的越多,那种焦虑感越是强烈。解决焦虑的唯一办法就是想办法解决当前问题。当慢慢地从消极的学习态度中调整过来,掌握的知识越多,那种焦虑感也随之消失。当然这个过程并不容易,不仅需要很好的毅力,也要根据自身情况找到问题的有效解决方法。
|
||||
|
||||
## 春招开始
|
||||
|
||||
三月份各个公司就开始春招了,那时候刚把一些基础知识简单地复习了一下,Leetcode 刷到了三四百题。但是没有后台研发相关的项目,于是花了一个星期左右用 PHP 做了一个微博系统。当时做简历特别痛苦,没内容可以写,看着其他人简历各种新技术,自己都没掌握,所以很虚。
|
||||
|
||||
## 阿里一轮游
|
||||
|
||||
最开始投的阿里,实验室大几届有个师兄在天猫精灵团队,所以给我内推了。于是我人生中第一场面试就是阿里,很自然地被虐了一遍。记得当时约好下午两点电话面试,午饭都没吃,怕吃完之后犯困影响状态,然后找了一个很安静又没人的地方呆到了两点,调整自己的状态。可是面试官突然打电话来说有个会议要开,所以推迟了大概一个小时。苦苦等到三点左右,面试正式开始,不出所料面得非常糟糕。首先自己表述的很有问题,很多内容没回答到关键点上,自己会的内容也不怎么继续扩展回答。其次知识掌握得确实不够,连线程安全、ThreadLocal、函数式编程都不会。虽然被虐的很惨,但是也有好处,知道了面试到底是怎样的,自己还有哪方面的不足,该怎么准备。
|
||||
|
||||
## 腾讯被鞭尸
|
||||
|
||||
第二场面试是腾讯,在经历了阿里的面试之后,并且又继续复习了一段时间,我对面试就比较有信心了。一面其实回答的挺理想的,虽然很多问题没有立马回答出来,但是经过面试官的耐心提示之后都能回答一些内容。当时面了一个半小时,面试体验特别好。印象比较深刻的题目有,阅读一个 Redis 源码,分析存在哪些问题。其实就是一个计数器实现的限流算法,会有临界值的问题,但是当时没回答出来,只能听面试官给我解释。还有一个微信扫二维码,这个过程发生了什么,也没回答得很好,不过面试官也很耐心地纠正我回答上的错误。一面顺利通过了,但是总监面挂了。总监面没有问什么技术问题,就是问了问项目和职业规划。自己的项目确实比较 Low,我自己在介绍的时候也说得很不堪。职业规划我说自己希望在一些方面深入学习,因为自己现在在这些方面还很薄弱... 面完之后我就知道挂了,因为整个面试过程我都特别虚,还主动说自己技术能力不行。不出所料,面完的当天晚上,状态变成了不合适。
|
||||
|
||||
但是过了几天,突然收到腾讯的电话,问我是否愿意去深圳参加面试(笔者学校在广州)。当然我毫不犹豫地答应了,很开心腾讯还能给我机会。经过了上一场面试的启示,这次面试我表现地非常自信,自己知道的知识都很有信心地表达出来,被问到不会的内容也不会那么慌张,和面试官探讨一些细节,然后说说自己的想法,还有自己看过相关的内容。由于这是腾讯云部门,对 Linux 内核和 C++ 有很高的要求,问了几个相关的问题我都没回答出来,比如如何实现守护进程,Linux 信号机制,Linux 线程的不可中断阻塞状态如何进入等等。除了这些问题,其它地回答的都还行。遗憾的是,当天晚上面试官打电话告知我面试没通过。但是他说我其它方面都很不错,所以问我愿不愿意参加腾讯云 Java 部门的招聘,于是第二天我又去了一个新的部门面试。
|
||||
|
||||
这次面试是在部门的会议室进行的,进到公司之后说实话没有自己想象中那么好,工位很挤环境一般。一开始就先随便聊聊,学校的研究工作,学习之类的。然后看了看项目,看完之后我就知道凉了一半,这个项目确实太水了,面试官看了之后没有接着问,也能感受到面试官有点嫌弃。然后他就问了一些基础知识,问到进程调度算法,面试官让我实现一个任务调度系统。因为是第一次手写代码,而且之前确实没考虑过这个问题,然后就胡乱写了一堆代码,特别乱,而且到处涂改。显然面试官是不满意的,写了也有十几分钟之后,我自己都知道已经凉了,然后面试官没让我接着写,也没给我任何提示,说就到这里,面试结束了,还有没有什么问题想问的。当然看过任务调度系统相关的文章会觉得挺容易的,比如使用时间轮实现等等。我依然记得面试官送我出门时候的热情,送我坐电梯的时候还很热情地和我说,非常感谢参加本次面试,辛苦了。
|
||||
|
||||
## 虎牙过于自信
|
||||
|
||||
经过了阿里和腾讯的面试之后,我觉得自己大概已经知道该怎么面试了,面试时候该注意什么,该怎么表达等等。而且腾讯面试表现也不差,虽然最后没通过。所以在虎牙面试的时候特别放松,觉得应该能通过。前面面的也都还行,虽然有几个问题没回答好,比如分析一下微博的时间线。通过了第一轮面试直接等第二轮,等到了晚上七点多才等到我。虎牙面试还是很注重技术的,虽然问的都不是很深入,只要简单回答到点上就不会接着问下去。二面也有一些问题没回答好,比如 ConcurrentHashMap 的并发机制,问 Spring 直接说不会。也有一些问题回答得比较乱,没有条理。但是我觉得大部分问题都回答的不错,应该能通过。可是面试完之后,面试官问有没有什么问题要问他,由于太过放松,我就问你们都加班到这么晚不吃饭吗,好饿啊,周六周日还加班吗... 问完之后面试官就很严肃了,说平常不加班的,我突然意识到了问题的严重性... 最后还是凉了。
|
||||
|
||||
## 百度第一个 Offer
|
||||
|
||||
被三家连续拒了之后,都开始怀疑自己了,不过还是提醒自己要保持信心。
|
||||
|
||||
幸运的是,百度的面试非常适合我,三轮都是技术面,而且手写算法题目居多,而我准备最多的是算法,所以很顺利通过了面试。但是面试表现并没有特别好,过了比较长的时间才被捞,而且是工程效率部门,做内部工具的,对个人成长并不好,所以不是特别满意。
|
||||
|
||||
## 网易游戏最好的面试体验
|
||||
|
||||
其实最开始没有打算投网易游戏的,因为被脉脉洗脑,已经放弃了做游戏。但是因为前面面试基本被拒了,担心没有实习 Offer,因此就试试看。
|
||||
|
||||
因为没有特别想去网易游戏,所以面试过程也比较放松,就当去聊聊天。面试官非常 nice,那天下午挤了很久地铁,比较口渴,然后面试官看我说得沙哑了,到门口帮我买了一瓶可乐,非常感激。面试之前我就提出我对 C++ 不熟悉,最近主要看 Java 的内容。面试官还是说没关系,尽量回答就好。当然最后我都把问题往 Java 那里回答了,比如 Map 的实现,内存管理等等。最后聊了一些玩过的游戏,就让我回去等消息。网易游戏就一轮面试,确实就一轮。周五参加的面试,下周一就给 Offer 了,效率特别高。
|
||||
|
||||
## 微众玄学面试
|
||||
|
||||
通过微众面试我自己都非常吃惊,一面的时候就简单自我介绍了一下,然后面试官开始介绍他自己的工作经历,以及现在部门在做的内容。之后问了我一个场景分析问题,我想了一会儿没想出来,于是面试官拿起草稿纸把各种需求详细说了一遍,然后把系统架构图也画了出来... 最后他问还有什么我优势的地方他没问到的,我问他怎么不问问算法题,他说笔试都通过了没必要再问。面完之后我觉得聊得很开心,但是技术问题没回答好,出乎意料收到了二面通知。二面没问技术,就让介绍了项目,再问问家住哪之类的问题,也顺利通过了。HR 面就不用介绍。收到了微众的 Offer,得知了部门是贷款科技部,非常核心,很吃香,近几年也在扩展一些业务,还是有点小心动的。虽然最后没选择去微众实习,但是一面面试官加了我微信,我很感谢他一面非常耐心给我讲解,并让我通过。他说我是他面试的第一顺位,也就是第一个面试者,所以会放宽很多,也希望我秋招能加入他们。
|
||||
|
||||
## 实习选择
|
||||
|
||||
其实最理想的是去百度实习,秋招也会容易很多。但是考虑到百度是在北京,部门很边缘,而且需要实习很长时间也不一定能转正,所以还是放弃了。最后只能在网易游戏和微众选,虽然自己不想做游戏,但是考虑到网易游戏的平台认可程度比微众好,秋招肯定会更容易一些。而且秋招如果还想进微众的话也会比较容易,因为面试官和 HR 都说秋招的时候会优先考虑我,所以最后还是去了网易游戏实习。
|
||||
|
||||
## 实习之前的快速学习期
|
||||
|
||||
经历了春招之后,认识到了自己身上的不足,比如交流表达能力的欠缺,知识积累得不够,项目深度不够。因此在实习之前的两三个月,开始针对这些问题逐个解决。
|
||||
|
||||
- 交流表达能力欠缺,就提前准备好各种非技术问题,然后对着镜子回答,把自己当成听众,并且也用录音机录下来。
|
||||
- 知识积累不够,采取的策略是保证广度优先,并且在重要的内容上保证深度。其实之前基础知识已经掌握的比较好了,再学其它技术的时候都有很多相同的地方,所以学起来很快。
|
||||
- 项目深度不够,就把那个微博系统做了一点改进,学了 Spring 之后改用 Java 实现。
|
||||
|
||||
## 不那么安心的实习
|
||||
|
||||
去实习的时候还是挺惊喜的,因为我被安排的工作是游戏引擎相关的,和自己的研究生方向紧密相关,我觉得做完实习项目之后自己的毕业论文也会比较有灵感。
|
||||
|
||||
但不幸的是,在去的第一天部门接待聚餐上,服务端主程就说,我们部门工作制是九九六,现在互联网都是九九六。在实习之前我了解的是实习生六点就可以走,而且只用上五天班,听到他这么一说心都凉透了,因为已经想好了晚上和周末时间用来复习。如果知道是九九六,我会选择去百度。
|
||||
|
||||
其实网易游戏部门氛围还是不错的,对员工很好,而且我的实习导师人也很好,在我生病的那几天很关心我。但是九九六的工作制对秋招复习还是有很大影响的,而且每天上下班花在路上的时间超过了两个小时,下班回寝室之后总想着看会儿视频休息一下,然后又要早早睡觉赶着第二天上班。没办法只能在上下班地铁上复习,还有就是午休时间接着复习。
|
||||
|
||||
## 秋招开始
|
||||
|
||||
实习之后已经是九月份了,那时候已经错过了所有提前批。而且实习的时候没怎么复习,九月初还是感觉没怎么准备充分,所以就又等了半个月才开始投简历。
|
||||
|
||||
但是这个时候和春招相比,已经把大部分后台研发相关的知识点过了一遍,很多重要的内容前前后后也看了十几遍,没有春招时候那么迷茫和焦虑。即使被问到没有掌握的知识,我也有把握通过讨论的方式,给出大概的思路,因为很多技术确实是相通的。
|
||||
|
||||
## 阿里看不懂的内部流程
|
||||
|
||||
秋招第一个投递的依然是阿里,最开始系统自动发起了一个新的流程,然后过了几天自动回绝了... 八月末的时候也找人内推了,但是又被阿里直接回绝了... 那时候已经觉得可能是春招面试表现太差,此生无缘阿里了。可是过了一段时间,正式校招的时候,阿里又发起了一个新的流程戏弄我,收到笔试通知的时候,我还犹豫了到底参不参加,因为那时候已经九月中旬,听说阿里已经没有 HC 了。而且按前面回绝我的态度,感觉即使笔试通过面试也通过不了。笔试那天晚上,本来准备看个电影放松一下,后来想了想还是参加了笔试,笔试各种机器学习和数学题,感觉拿错了试卷,笔试完我已经把阿里从我的公司进度列表中删除了,不再纠结阿里。可是过了一段时间收到阿里的面试通知,我以为是走走形式,可能参加笔试的人很少了,所以才选中我参加面试。那时候阿里招聘官网状态一排的已回绝,让我对阿里有一种恐惧感,觉得面试肯定挂。但是真正面试的时候却意外的顺利,收到二面通知的时候特别激动,然后面完二面又让直接等 HR 面,HR 面虽然不是很理想,但是没有很大的问题。又过了很长一段时间,在我去深圳参加腾讯招聘的高铁上,收到了高德地图 HR 的电话,问是否愿意去。虽然得知部门在北京有点小失落,但是还是很开心终于被阿里认可了,摆脱了对阿里的恐惧。
|
||||
|
||||
实验室上届毕业在阿里云的大佬某天突然和我说,他们部门有新的 HC,让我把简历发给他,他要帮我内推,会帮我安排一场线下面试,如果通过的话,到时候和高德的 HR 沟通一下,直接把我从高德捞过来。很感谢大佬向他老大极力推荐我,给我了这次面试机会。线下面试也很顺利,聊聊实习项目,问问我的开源博客,然后问些 Paxos 等分布式的问题,还有就是手写代码,信号量实现生产者消费者,以及一个位运算的问题。其实位运算的问题面试的时候写的不完善,面试官让我之后完善了再发给他,因为面试一个多小时有点长了。过后我写了详细文档讲解了思路,以及使用 JUnit 进行了详细的单元测试,把文档和代码都发给了他。现在面试已经通过了,但是最近阿里集团 HC 比较紧张,也不知道能不能批到 HC。
|
||||
|
||||
## 百度又是不那么满意的部门
|
||||
|
||||
虽然阿里是最先开始流程,但是第一个参加面试的是百度。因为实习的时候通过了百度的面试,所以这次面试还是比较有信心的。百度面试连续三天,都在同一个地方,最后签约也在同一个地方。还记得每次都坐一个小时左右的地铁去那里,路线已经非常熟悉了,和每天去实习的感觉类似。百度面试比较注重技术,三轮面试基本都是问技术问题,而且问的也比较深入,内容也非常广。但是面的不是那么理想,有两点原因,首先是因为确实有些知识点还没掌握好,比如 AC 自动机,系统故障分析等等;其次是对实习项目的描述上还不够好,没有把实习内容的闪光点描述出来,也没有讲清楚为什么做这个项目,自己通过什么方法去做,以及最后的结果。
|
||||
|
||||
最后百度给了白菜价,部门是企业智能平台,主要是内部系统,虽然会接触到机器学习和大数据。
|
||||
|
||||
## 腾讯虐我千百遍
|
||||
|
||||
秋招腾讯第一场面试和实习参加腾讯面试的感觉非常像,第一轮技术面感觉很好,手写堆排序算法,二部图分析等等。面完之后通知待会儿二面,听到之后还是很激动的,觉得这次应该没问题了。我在等二面的时候,碰到了室友(他经常不住宿舍,所以不清楚他也去面试),聊着聊着居然发现我两是同一个面试官,而且他是来二面的,也就是等一下我两就要一前一后进去面试。二面的感觉和实习二面非常像,非技术问题回答的支支吾吾,然后面试官开始质疑我说的内容,给我压力,我没有当场反驳,就说了哦,好像是这样的。因为面试官全程都绷着脸,所以我也比较紧张,很多问题没回答好。过了几天,室友和我说收到 HR 面试通知了,我去官网看了一下状态,已经变成了熟悉的不合适。这次面试失败的主要原因是自己在应对这种压力时处理地不是很好,主要体现在失去信心以及紧张。解决方法也简单,做好充分准备来保持信心,受到质疑的时候积极反驳,紧张的时候计时调整心态,可以试试深呼吸或者喝水。
|
||||
|
||||
因为实习有被捞起来的经历,所以被拒之后我特别希望能继续被捞起来,然后把简历上的面试城市改成了深圳。苦苦等到深圳场面试的前几天,在不经意的一个下午手机突然响了,我记得是短信邮件同时收到面试通知。于是又开始了新一轮被腾讯虐的面试之旅。
|
||||
|
||||
一面和之前一样也是意外地顺利,虽然问了一些 C++ 的问题,但是我都说到 Java 相关的实现上。在一些问题上确实回答的深度不够,比如网络编程里面的水平触发和边缘触发等问题。然后问了几个算法,本来要求手写,我说我实现过,所以就讲了讲思路。面试和腾讯第一场面试一样持续了一个半小时,面试官也很好,很多问题都会给提示,即使最开始回答的有问题。二面面试官也很好,问了问实习项目,然后再聊一聊一些技术,经过了之前的面试,到这次面试真的就像在聊天一样而不是面试,我们都会说一些对技术上的理解。HR 面其实面得很差,对于非技术问题的吹水能力我还是不太行。最终和我预期的一样,给了我 SP 的 Offer,因为觉得自己面得还可以,但是也不够好到给 SSP,有些 C++ 问题还是没回答的特别好。
|
||||
|
||||
## 头条意外的惊喜
|
||||
|
||||
之前看到学弟收到头条的 Offer,薪资非常诱人,所以也想去试试。也听说头条面试难度非常大,主要考察手写算法,因为自己算法方面准备得比较充分,所以觉得会比较顺利,但是也没有特别高的预期。前两面中规中矩,算法题和其它问题我都回答的比较好,到三面的时候,问了一个错排问题,其实最开始我给了正确的递推公式,但不是面试官想要的答案,所以让我再想想。我想了十几分钟还是觉得没问题,那时候觉得自己已经凉了,因为面试官一直不满意。后面的几个问题也没回答的很好,分析一个 SQL 语句的具体执行过程,比如会怎么利用索引,怎么优化之类的,虽然在他的提示下还是回答了,但是感觉并不好。面完之后我立马查了一下那个错排问题,证实了我的答案是正确的,于是写了一个详细的文档,联系 HR 让她发给面试官。出乎意料的是,HR 让我不用担心,他说面试官对我的评价很好... 不过最后还是让她把文档发给了面试官。之后收到了加面通知,头条加面有两种情况,一是三轮评级都是 4 可以评 SSP,二是面试官评价差别很大,再面一轮决定是否录用。收到加面的时候完全不知道自己属于哪一种,感觉两种情况都有可能。加面回答的也不好,主要是问项目,面了 25 分钟就草草结束,最后面试官说有些内容需要找一些文献参考参考。面完之后我觉得,即使我属于第一种要评 SSP 的情况,加面面的那么差应该也没希望了。苦苦等了好多天之后,最后确定是 SSP 之后,还是很惊喜的,感觉是对自己这么长时间复习的一个认可。
|
||||
|
||||
## 顺丰最后的保底
|
||||
|
||||
投顺丰是因为九月中旬很多公司都结束了招聘,所以那时候比较慌,就投了顺丰当做保底,顺便也练练手。最开始还担心顺丰笔试没通过,因为编程题最后一题没做出来,那题的题目都出错了,而且题目是网上直接 copy 过来的,网上的源码都不能通过,更别说我自己的实现了。顺丰面试主要问了数据库的内容,而且问的特别深,几乎把每种日志的实现和作用都问了一遍。面顺丰的时候也比较早,那时候有些问题的回答上没有组织好,回答得比较凌乱,虽然最后也算给了一个小 SP。
|
||||
|
||||
## 华为特别纠结的部门
|
||||
|
||||
去华为面试确实是没有压力的,因为都知道华为面试不怎么问技术,虽然还是问了我一些技术问题,不过不是问的很深。面试主要介绍项目,我对自己的实习项目还是比较有信心的,因为觉得做的确实不错,而且面了很多场了,知道该怎么介绍项目。面试官问我个人意愿,我说自己对分布式中间件等比较感兴趣,于是面试官把我推荐到了 Cloud Bu。本来没打算签华为的,现场签约也就去看看到底给我开多少。最开始其实给我开了十四级最高的薪资,我本来不是很想去,虽然对这个部门感兴趣,但是薪资确实比不上头条。然后随口问了一句可不可以给十五级,本来 HR 说是可以试着申请一下,不过最后没申请成功。
|
||||
|
||||
## 技术博客
|
||||
|
||||
最后安利一下自己的技术博客:[CS-Notes](https://github.com/CyC2018/CS-Notes),虽然现在还有很多不完善的地方,但以后会不断改进。
|
||||
|
||||
## 小结
|
||||
|
||||
很多人都说,面试和考试一样,要背很多没用的东西。最开始我也认同这种看法,可是参加了几场面试之后,我就不这么认为了。因为面试出的问题,有很多是实际开发中碰到的,所以准备面试相当于提前做入职准备。而且面试中考察的思维能力、交流表达能力、应对压力能力,都是真正工作中所需要的。
|
||||
|
||||
我觉得自己比别人做的好的地方是,有很强烈的想找到好工作的意愿,才驱使我不断学习,所以态度很重要。
|
||||
|
||||
信心源自于充分准备,有了信心,面试的时候才能游刃有余。而毫无依据的自我感觉良好,在每次失败之后都看不到自身的不足,而是怪罪于外界因素。
|
||||
|
||||
做好自己的简历,我在简历上花了很长时间,只要允许,我都会用这个简历给面试官演示:[个人简历](https://cyc2018.github.io)。
|
46
Additional.md
Normal file
@ -0,0 +1,46 @@
|
||||
# 前言
|
||||
|
||||
本文档提供博客内容的补充资料,记录一些还没写又很重要的内容。欢迎补充!
|
||||
|
||||
格式:\[资料名称\]\[标签1\]\[标签2\]...
|
||||
|
||||
|
||||
# 系统设计
|
||||
|
||||
- [[system-design-primer][Github]](https://github.com/donnemartin/system-design-primer)
|
||||
- [[Leetcode / Interview Questions][题集]](https://leetcode.com/discuss/interview-question/?orderBy=most_votes)
|
||||
- [[系统设计面试题精选][Gitbook]](https://soulmachine.gitbooks.io/system-design/content/cn/)
|
||||
- [[海量数据面试题]](https://samanthachen.github.io/2016/08/01/%E6%B5%B7%E9%87%8F%E6%95%B0%E6%8D%AE%E9%9D%A2%E8%AF%95%E9%A2%98/)
|
||||
- [[前端经典面试题: 从输入 URL 到页面加载发生了什么?][具体问题]](https://segmentfault.com/a/1190000006879700)
|
||||
- [[秒杀系统架构分析与实战][具体问题]](https://my.oschina.net/xianggao/blog/524943)
|
||||
- [[微信二维码登录原理][具体问题]](https://zhuanlan.zhihu.com/p/22325152?refer=bittiger)
|
||||
- [[Create a TinyURL System][具体问题]](https://github.com/CyC2018/CS-Notes)
|
||||
- [[Design a Key-Value Store (Part I)][具体问题]](http://blog.gainlo.co/index.php/2016/06/14/design-a-key-value-store-part-i/)
|
||||
- [[坦率地讲 服务熔断 & 服务降级][知识点]](http://lexuslee.me/2018/02/01/2018-01-18-Service-fallback/)
|
||||
- [[理解 HTTP 幂等性][知识点]](https://www.cnblogs.com/weidagang2046/archive/2011/06/04/idempotence.html)
|
||||
- [[接口限流算法][知识点]](https://blog.csdn.net/ljj821061514/article/details/52512943)
|
||||
- [[微服务学习资料汇总][知识点]](https://www.infoq.cn/article/2014%2F07%2Fmicroservice-learning-resources)
|
||||
- [[理解 RESTful 架构][知识点]](http://www.ruanyifeng.com/blog/2011/09/restful.html)
|
||||
- [[MapReduce 算法][知识点]](https://github.com/xuelangZF/CS_Offer/blob/master/Others/Hadoop_Spark.md)
|
||||
|
||||
# Spring
|
||||
|
||||
- [[Spring 揭秘][书籍]](https://book.douban.com/subject/3897837/)
|
||||
- [[69 道 Spring 面试题和答案][面试题集锦]](http://ifeve.com/spring-interview-questions-and-answers/)
|
||||
- [[Spring 面试题][面试题集锦]](https://github.com/Homiss/Java-interview-questions/blob/master/%E6%A1%86%E6%9E%B6/Spring%20%E9%9D%A2%E8%AF%95%E9%A2%98.md)
|
||||
|
||||
# 中间件
|
||||
|
||||
- [[RabbitMQ 实战][书籍]](https://book.douban.com/subject/26649178/)
|
||||
- [[从 Paxos 到 Zookeeper][书籍]](https://book.douban.com/subject/26292004/)]
|
||||
- [[Apache Dubbo][文档]](http://dubbo.apache.org/zh-cn/)
|
||||
- [[nginx 快速入门之基本原理篇][入门]](https://zhuanlan.zhihu.com/p/31196264)
|
||||
- [[深入理解 Nginx][书籍]](https://book.douban.com/subject/22793675/)
|
||||
|
||||
# 编程语言思想
|
||||
|
||||
- [[函数式编程初探][入门]](http://www.ruanyifeng.com/blog/2012/04/functional_programming.html)]
|
||||
- [[函数式编程][全面]](https://coolshell.cn/articles/10822.html)
|
||||
- [[闭包][文档]](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Closures)
|
||||
- [[尾调用优化]](http://www.ruanyifeng.com/blog/2015/04/tail-call.html)
|
||||
|
@ -41,6 +41,7 @@
|
||||
|
||||
- [Java 编程思想](https://book.douban.com/subject/2130190/)
|
||||
- [Effective java 中文版](https://book.douban.com/subject/3360807/)
|
||||
- [深入Java虚拟机(原书第2版)](https://book.douban.com/subject/1138768/)
|
||||
- [深入理解 Java 虚拟机](https://book.douban.com/subject/24722612/)
|
||||
- [Java 并发编程实战](https://book.douban.com/subject/10484692/)
|
||||
- [精通 Spring 4.x](https://book.douban.com/subject/26952826/)
|
||||
|
80
README.md
@ -12,151 +12,151 @@
|
||||
|
||||
### :pencil2: 算法
|
||||
|
||||
- [剑指 Offer 题解](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/剑指%20offer%20题解.md)
|
||||
- [剑指 Offer 题解](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/剑指%20offer%20题解.md)
|
||||
|
||||
目录根据原书第二版进行编排,代码和原书有所不同,尽量比原书更简洁。
|
||||
|
||||
- [Leetcode 题解](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/Leetcode%20题解.md)
|
||||
- [Leetcode 题解](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Leetcode%20题解.md)
|
||||
|
||||
对题目做了一个大致分类,并对每种题型的解题思路做了总结。
|
||||
|
||||
- [算法](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/算法.md)
|
||||
- [算法](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/算法.md)
|
||||
|
||||
排序、并查集、栈和队列、红黑树、散列表。
|
||||
|
||||
### :computer: 操作系统
|
||||
|
||||
- [计算机操作系统](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/计算机操作系统.md)
|
||||
- [计算机操作系统](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/计算机操作系统.md)
|
||||
|
||||
进程管理、内存管理、设备管理、链接。
|
||||
|
||||
- [Linux](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/Linux.md)
|
||||
- [Linux](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Linux.md)
|
||||
|
||||
基本实现原理以及基本操作。
|
||||
|
||||
### :cloud: 网络
|
||||
|
||||
- [计算机网络](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/计算机网络.md)
|
||||
- [计算机网络](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/计算机网络.md)
|
||||
|
||||
物理层、链路层、网络层、运输层、应用层。
|
||||
|
||||
- [HTTP](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/HTTP.md)
|
||||
- [HTTP](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/HTTP.md)
|
||||
|
||||
方法、状态码、Cookie、缓存、连接管理、HTTPs、HTTP 2.0。
|
||||
|
||||
- [Socket](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/Socket.md)
|
||||
- [Socket](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Socket.md)
|
||||
|
||||
I/O 模型、I/O 多路复用。
|
||||
|
||||
### :couple: 面向对象
|
||||
|
||||
- [设计模式](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/设计模式.md)
|
||||
- [设计模式](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/设计模式.md)
|
||||
|
||||
实现了 Gof 的 23 种设计模式。
|
||||
|
||||
- [面向对象思想](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/面向对象思想.md)
|
||||
- [面向对象思想](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/面向对象思想.md)
|
||||
|
||||
三大原则(继承、封装、多态)、类图、设计原则。
|
||||
|
||||
### :floppy_disk: 数据库
|
||||
|
||||
- [数据库系统原理](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/数据库系统原理.md)
|
||||
- [数据库系统原理](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/数据库系统原理.md)
|
||||
|
||||
事务、锁、隔离级别、MVCC、间隙锁、范式。
|
||||
|
||||
- [SQL](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/SQL.md)
|
||||
- [SQL](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/SQL.md)
|
||||
|
||||
SQL 基本语法。
|
||||
|
||||
- [Leetcode-Database 题解](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/Leetcode-Database%20题解.md)
|
||||
- [Leetcode-Database 题解](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Leetcode-Database%20题解.md)
|
||||
|
||||
Leetcode 上数据库题目的解题记录。
|
||||
|
||||
- [MySQL](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/MySQL.md)
|
||||
- [MySQL](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/MySQL.md)
|
||||
|
||||
存储引擎、索引、查询优化、切分、复制。
|
||||
|
||||
- [Redis](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/Redis.md)
|
||||
- [Redis](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Redis.md)
|
||||
|
||||
五种数据类型、字典和跳跃表数据结构、使用场景、和 Memcache 的比较、淘汰策略、持久化、文件事件的 Reactor 模式、复制。
|
||||
|
||||
### :coffee: Java
|
||||
|
||||
- [Java 基础](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/Java%20基础.md)
|
||||
- [Java 基础](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Java%20基础.md)
|
||||
|
||||
不会涉及很多基本语法介绍,主要是一些实现原理以及关键特性。
|
||||
|
||||
- [Java 容器](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/Java%20容器.md)
|
||||
- [Java 容器](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Java%20容器.md)
|
||||
|
||||
源码分析:ArrayList、Vector、CopyOnWriteArrayList、LinkedList、HashMap、ConcurrentHashMap、LinkedHashMap、WeekHashMap。
|
||||
源码分析:ArrayList、Vector、CopyOnWriteArrayList、LinkedList、HashMap、ConcurrentHashMap、LinkedHashMap、WeakHashMap。
|
||||
|
||||
- [Java 并发](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/Java%20并发.md)
|
||||
- [Java 并发](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Java%20并发.md)
|
||||
|
||||
线程使用方式、两种互斥同步方法、线程协作、JUC、线程安全、内存模型、锁优化。
|
||||
|
||||
- [Java 虚拟机](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/Java%20虚拟机.md)
|
||||
- [Java 虚拟机](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Java%20虚拟机.md)
|
||||
|
||||
运行时数据区域、垃圾收集、类加载。
|
||||
|
||||
- [Java I/O](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/Java%20IO.md)
|
||||
- [Java I/O](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Java%20IO.md)
|
||||
|
||||
NIO 的原理以及实例。
|
||||
|
||||
### :bulb: 系统设计
|
||||
|
||||
- [系统设计基础](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/系统设计基础.md)
|
||||
- [系统设计基础](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/系统设计基础.md)
|
||||
|
||||
性能、伸缩性、扩展性、可用性、安全性
|
||||
|
||||
- [分布式](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/分布式.md)
|
||||
- [分布式](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/分布式.md)
|
||||
|
||||
分布式锁、分布式事务、CAP、BASE、Paxos、Raft
|
||||
|
||||
- [集群](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/集群.md)
|
||||
- [集群](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/集群.md)
|
||||
|
||||
负载均衡、Session 管理
|
||||
|
||||
- [攻击技术](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/攻击技术.md)
|
||||
- [攻击技术](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/攻击技术.md)
|
||||
|
||||
XSS、CSRF、SQL 注入、DDoS
|
||||
|
||||
- [缓存](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/缓存.md)
|
||||
- [缓存](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/缓存.md)
|
||||
|
||||
缓存特征、缓存位置、缓存问题、数据分布、一致性哈希、LRU、CDN
|
||||
|
||||
- [消息队列](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/消息队列.md)
|
||||
- [消息队列](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/消息队列.md)
|
||||
|
||||
消息处理模型、使用场景、可靠性
|
||||
|
||||
### :hammer: 工具
|
||||
|
||||
- [Git](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/Git.md)
|
||||
- [Git](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Git.md)
|
||||
|
||||
一些 Git 的使用和概念。
|
||||
|
||||
- [Docker](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/Docker.md)
|
||||
- [Docker](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/Docker.md)
|
||||
|
||||
Docker 基本原理。
|
||||
|
||||
- [正则表达式](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/正则表达式.md)
|
||||
- [正则表达式](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/正则表达式.md)
|
||||
|
||||
正则表达式基本语法。
|
||||
|
||||
- [构建工具](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/构建工具.md)
|
||||
- [构建工具](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/构建工具.md)
|
||||
|
||||
构建工具的基本概念、主流构建工具介绍。
|
||||
|
||||
### :speak_no_evil: 编码实践
|
||||
|
||||
- [重构](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/重构.md)
|
||||
- [重构](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/重构.md)
|
||||
|
||||
参考 重构 改善既有代码的设计。
|
||||
|
||||
- [代码可读性](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/代码可读性.md)
|
||||
- [代码可读性](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/代码可读性.md)
|
||||
|
||||
参考 编写可读代码的艺术。
|
||||
|
||||
- [代码风格规范](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/代码风格规范.md)
|
||||
- [代码风格规范](https://github.com/CyC2018/CS-Notes/blob/master/docs/notes/代码风格规范.md)
|
||||
|
||||
Google 开源项目的代码风格规范。
|
||||
|
||||
@ -168,10 +168,6 @@
|
||||
|
||||
学习笔记不是从网上到处拼凑而来,除了少部分引用书上和技术文档的原文,其余都是笔者的原创。在您引用本仓库内容或者对内容进行修改演绎时,请遵循文末的开源协议,谢谢。
|
||||
|
||||
#### BookList
|
||||
|
||||
本仓库参考的书目:[BOOKLIST](https://github.com/CyC2018/Interview-Notebook/blob/master/BOOKLIST.md)。
|
||||
|
||||
#### How To Contribute
|
||||
|
||||
笔记内容是笔者一个字一个字打上去的,难免会有一些笔误,如果发现笔误可直接对相应文档进行编辑修改。
|
||||
@ -180,6 +176,10 @@
|
||||
|
||||
欢迎在 Issue 中提交对本仓库的改进建议~
|
||||
|
||||
#### BookList
|
||||
|
||||
本仓库参考的书目:[BOOKLIST](https://github.com/CyC2018/Interview-Notebook/blob/master/BOOKLIST.md)。
|
||||
|
||||
#### Typesetting
|
||||
|
||||
笔记内容按照 [中文文案排版指北](https://mazhuang.org/wiki/chinese-copywriting-guidelines/) 进行排版,以保证内容的可读性。
|
||||
@ -232,6 +232,10 @@ Power by [logomakr](https://logomakr.com/).
|
||||
<a href="https://github.com/mafulong">
|
||||
<img src="https://avatars1.githubusercontent.com/u/24795000?s=400&v=4" width="50px">
|
||||
</a>
|
||||
<a href="https://github.com/yanglbme">
|
||||
<img src="https://avatars1.githubusercontent.com/u/21008209?s=400&v=4" width="50px">
|
||||
</a>
|
||||
|
||||
|
||||
#### License
|
||||
|
||||
|
0
docs/.nojekyll
Normal file
53
docs/README.md
Normal file
@ -0,0 +1,53 @@
|
||||
# 算法
|
||||
|
||||
- [剑指 Offer 题解](notes/剑指%20offer%20题解.md)
|
||||
- [Leetcode 题解](notes/Leetcode%20题解)
|
||||
- [算法](notes/算法.md)
|
||||
|
||||
# 操作系统
|
||||
|
||||
- [计算机操作系统](notes/计算机操作系统.md)
|
||||
- [Linux](notes/Linux.md)
|
||||
|
||||
# 网络
|
||||
|
||||
- [计算机网络](notes/计算机网络.md)
|
||||
- [HTTP](notes/HTTP.md)
|
||||
- [Sockets](notes/Sockets.md)
|
||||
|
||||
# 面向对象
|
||||
|
||||
- [设计模式](notes/设计模式.md)
|
||||
- [面向对象思想](notes/面向对象思想.md)
|
||||
|
||||
# 数据库
|
||||
|
||||
- [数据库系统原理](notes/数据库系统原理.md)
|
||||
- [SQL](notes/SQL.md)
|
||||
- [Leetcode-Database 题解](notes/Leetcode-Database%20题解.md)
|
||||
- [MySQL](notes/MySQL.md)
|
||||
- [Redis](notes/Redis.md)
|
||||
|
||||
# Java
|
||||
|
||||
- [Java 基础](notes/Java%20基础.md)
|
||||
- [Java 容器](notes/Java%20容器.md)
|
||||
- [Java 并发](notes/Java%20并发.md)
|
||||
- [Java 虚拟机](notes/Java%20虚拟机.md)
|
||||
- [Java I/O](notes/Java%20IO.md)
|
||||
|
||||
# 系统设计
|
||||
|
||||
- [系统设计基础](notes/系统设计基础.md)
|
||||
- [分布式](notes/分布式.md)
|
||||
- [集群](notes/集群.md)
|
||||
- [攻击技术](notes/攻击技术.md)
|
||||
- [缓存](notes/缓存.md)
|
||||
- [消息队列](notes/消息队列.md)
|
||||
|
||||
# 工具
|
||||
|
||||
- [Git](notes/Git.md)
|
||||
- [Docker](notes/Docker.md)
|
||||
- [正则表达式](notes/正则表达式.md)
|
||||
- [构建工具](notes/构建工具.md)
|
13
docs/_coverpage.md
Normal file
@ -0,0 +1,13 @@
|
||||
<img width="150px" src="_media/LogoMakr_1J56bI.png">
|
||||
|
||||
# CS-Notes
|
||||
|
||||
> Computer Sicence Learning Notes.
|
||||
|
||||
- Algorithm
|
||||
- Computer Networks
|
||||
- Operating System
|
||||
- ...
|
||||
|
||||
[Get Started](README.md)
|
||||
|
BIN
docs/_media/LogoMakr_1J56bI.png
Normal file
After Width: | Height: | Size: 56 KiB |
BIN
docs/_media/logomakr-3sxxzw-128x128.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
6
docs/_navbar.md
Normal file
@ -0,0 +1,6 @@
|
||||
- Translations
|
||||
- [:uk: English](/)
|
||||
- [:cn: 中文](/zh-cn/)
|
||||
- [:de: Deutsch](/de-de/)
|
||||
- [:es: Spanish](/es/)
|
||||
- [:ru: Russian](/ru/)
|
53
docs/_sidebar.md
Normal file
@ -0,0 +1,53 @@
|
||||
- :pencil2: 算法
|
||||
|
||||
- [剑指 Offer 题解](notes/剑指%20offer%20题解.md)
|
||||
- [Leetcode 题解](notes/Leetcode%20题解)
|
||||
- [算法](notes/算法.md)
|
||||
|
||||
- :computer: 操作系统
|
||||
|
||||
- [计算机操作系统](notes/计算机操作系统.md)
|
||||
- [Linux](notes/Linux.md)
|
||||
|
||||
- :cloud: 网络
|
||||
|
||||
- [计算机网络](notes/计算机网络.md)
|
||||
- [HTTP](notes/HTTP.md)
|
||||
- [Sockets](notes/Sockets.md)
|
||||
|
||||
- :couple: 面向对象
|
||||
|
||||
- [设计模式](notes/设计模式.md)
|
||||
- [面向对象思想](notes/面向对象思想.md)
|
||||
|
||||
- :floppy_disk: 数据库
|
||||
|
||||
- [数据库系统原理](notes/数据库系统原理.md)
|
||||
- [SQL](notes/SQL.md)
|
||||
- [Leetcode-Database 题解](notes/Leetcode-Database%20题解.md)
|
||||
- [MySQL](notes/MySQL.md)
|
||||
- [Redis](notes/Redis.md)
|
||||
|
||||
- :coffee: Java
|
||||
|
||||
- [Java 基础](notes/Java%20基础.md)
|
||||
- [Java 容器](notes/Java%20容器.md)
|
||||
- [Java 并发](notes/Java%20并发.md)
|
||||
- [Java 虚拟机](notes/Java%20虚拟机.md)
|
||||
- [Java I/O](notes/Java%20IO.md)
|
||||
|
||||
- :bulb: 系统设计
|
||||
|
||||
- [系统设计基础](notes/系统设计基础.md)
|
||||
- [分布式](notes/分布式.md)
|
||||
- [集群](notes/集群.md)
|
||||
- [攻击技术](notes/攻击技术.md)
|
||||
- [缓存](notes/缓存.md)
|
||||
- [消息队列](notes/消息队列.md)
|
||||
|
||||
- :hammer:工具
|
||||
|
||||
- [Git](notes/Git.md)
|
||||
- [Docker](notes/Docker.md)
|
||||
- [正则表达式](notes/正则表达式.md)
|
||||
- [构建工具](notes/构建工具.md)
|
2050
docs/_style/bootstrap-4.0.0-dist/css/bootstrap-grid.css
vendored
Normal file
7
docs/_style/bootstrap-4.0.0-dist/css/bootstrap-grid.min.css
vendored
Normal file
330
docs/_style/bootstrap-4.0.0-dist/css/bootstrap-reboot.css
vendored
Normal file
@ -0,0 +1,330 @@
|
||||
/*!
|
||||
* Bootstrap Reboot v4.0.0 (https://getbootstrap.com)
|
||||
* Copyright 2011-2018 The Bootstrap Authors
|
||||
* Copyright 2011-2018 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
|
||||
*/
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html {
|
||||
font-family: sans-serif;
|
||||
line-height: 1.15;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
-ms-text-size-adjust: 100%;
|
||||
-ms-overflow-style: scrollbar;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
|
||||
@-ms-viewport {
|
||||
width: device-width;
|
||||
}
|
||||
|
||||
article, aside, dialog, figcaption, figure, footer, header, hgroup, main, nav, section {
|
||||
display: block;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
||||
font-size: 1rem;
|
||||
font-weight: 400;
|
||||
line-height: 1.5;
|
||||
color: #212529;
|
||||
text-align: left;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
[tabindex="-1"]:focus {
|
||||
outline: 0 !important;
|
||||
}
|
||||
|
||||
hr {
|
||||
box-sizing: content-box;
|
||||
height: 0;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
abbr[title],
|
||||
abbr[data-original-title] {
|
||||
text-decoration: underline;
|
||||
-webkit-text-decoration: underline dotted;
|
||||
text-decoration: underline dotted;
|
||||
cursor: help;
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
address {
|
||||
margin-bottom: 1rem;
|
||||
font-style: normal;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul,
|
||||
dl {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
ol ol,
|
||||
ul ul,
|
||||
ol ul,
|
||||
ul ol {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
dt {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
dd {
|
||||
margin-bottom: .5rem;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
dfn {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
sub,
|
||||
sup {
|
||||
position: relative;
|
||||
font-size: 75%;
|
||||
line-height: 0;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -.25em;
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -.5em;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #007bff;
|
||||
text-decoration: none;
|
||||
background-color: transparent;
|
||||
-webkit-text-decoration-skip: objects;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #0056b3;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
a:not([href]):not([tabindex]) {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:not([href]):not([tabindex]):hover, a:not([href]):not([tabindex]):focus {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:not([href]):not([tabindex]):focus {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
pre,
|
||||
code,
|
||||
kbd,
|
||||
samp {
|
||||
font-family: monospace, monospace;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
pre {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
overflow: auto;
|
||||
-ms-overflow-style: scrollbar;
|
||||
}
|
||||
|
||||
figure {
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
img {
|
||||
vertical-align: middle;
|
||||
border-style: none;
|
||||
}
|
||||
|
||||
svg:not(:root) {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
caption {
|
||||
padding-top: 0.75rem;
|
||||
padding-bottom: 0.75rem;
|
||||
color: #6c757d;
|
||||
text-align: left;
|
||||
caption-side: bottom;
|
||||
}
|
||||
|
||||
th {
|
||||
text-align: inherit;
|
||||
}
|
||||
|
||||
label {
|
||||
display: inline-block;
|
||||
margin-bottom: .5rem;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
button:focus {
|
||||
outline: 1px dotted;
|
||||
outline: 5px auto -webkit-focus-ring-color;
|
||||
}
|
||||
|
||||
input,
|
||||
button,
|
||||
select,
|
||||
optgroup,
|
||||
textarea {
|
||||
margin: 0;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
button,
|
||||
input {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
button,
|
||||
select {
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
button,
|
||||
html [type="button"],
|
||||
[type="reset"],
|
||||
[type="submit"] {
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
|
||||
button::-moz-focus-inner,
|
||||
[type="button"]::-moz-focus-inner,
|
||||
[type="reset"]::-moz-focus-inner,
|
||||
[type="submit"]::-moz-focus-inner {
|
||||
padding: 0;
|
||||
border-style: none;
|
||||
}
|
||||
|
||||
input[type="radio"],
|
||||
input[type="checkbox"] {
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
input[type="date"],
|
||||
input[type="time"],
|
||||
input[type="datetime-local"],
|
||||
input[type="month"] {
|
||||
-webkit-appearance: listbox;
|
||||
}
|
||||
|
||||
textarea {
|
||||
overflow: auto;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
min-width: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
legend {
|
||||
display: block;
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
padding: 0;
|
||||
margin-bottom: .5rem;
|
||||
font-size: 1.5rem;
|
||||
line-height: inherit;
|
||||
color: inherit;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
progress {
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
[type="number"]::-webkit-inner-spin-button,
|
||||
[type="number"]::-webkit-outer-spin-button {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
[type="search"] {
|
||||
outline-offset: -2px;
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
[type="search"]::-webkit-search-cancel-button,
|
||||
[type="search"]::-webkit-search-decoration {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
font: inherit;
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
|
||||
output {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
summary {
|
||||
display: list-item;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
template {
|
||||
display: none;
|
||||
}
|
||||
|
||||
[hidden] {
|
||||
display: none !important;
|
||||
}
|
||||
/*# sourceMappingURL=bootstrap-reboot.css.map */
|
8
docs/_style/bootstrap-4.0.0-dist/css/bootstrap-reboot.min.css
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
/*!
|
||||
* Bootstrap Reboot v4.0.0 (https://getbootstrap.com)
|
||||
* Copyright 2011-2018 The Bootstrap Authors
|
||||
* Copyright 2011-2018 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
|
||||
*/*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:transparent}@-ms-viewport{width:device-width}article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}dfn{font-style:italic}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent;-webkit-text-decoration-skip:objects}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto;-ms-overflow-style:scrollbar}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg:not(:root){overflow:hidden}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important}
|
||||
/*# sourceMappingURL=bootstrap-reboot.min.css.map */
|
8975
docs/_style/bootstrap-4.0.0-dist/css/bootstrap.css
vendored
Normal file
1
docs/_style/bootstrap-4.0.0-dist/css/bootstrap.css.map
Normal file
7
docs/_style/bootstrap-4.0.0-dist/css/bootstrap.min.css
vendored
Normal file
6328
docs/_style/bootstrap-4.0.0-dist/js/bootstrap.bundle.js
vendored
Normal file
7
docs/_style/bootstrap-4.0.0-dist/js/bootstrap.bundle.min.js
vendored
Normal file
3894
docs/_style/bootstrap-4.0.0-dist/js/bootstrap.js
vendored
Normal file
1
docs/_style/bootstrap-4.0.0-dist/js/bootstrap.js.map
Normal file
7
docs/_style/bootstrap-4.0.0-dist/js/bootstrap.min.js
vendored
Normal file
1
docs/_style/bootstrap-4.0.0-dist/js/bootstrap.min.js.map
Normal file
2050
docs/_style/bootstrap/css/bootstrap-grid.css
vendored
Normal file
1
docs/_style/bootstrap/css/bootstrap-grid.css.map
Normal file
7
docs/_style/bootstrap/css/bootstrap-grid.min.css
vendored
Normal file
1
docs/_style/bootstrap/css/bootstrap-grid.min.css.map
Normal file
330
docs/_style/bootstrap/css/bootstrap-reboot.css
vendored
Normal file
@ -0,0 +1,330 @@
|
||||
/*!
|
||||
* Bootstrap Reboot v4.0.0 (https://getbootstrap.com)
|
||||
* Copyright 2011-2018 The Bootstrap Authors
|
||||
* Copyright 2011-2018 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
|
||||
*/
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html {
|
||||
font-family: sans-serif;
|
||||
line-height: 1.15;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
-ms-text-size-adjust: 100%;
|
||||
-ms-overflow-style: scrollbar;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
|
||||
@-ms-viewport {
|
||||
width: device-width;
|
||||
}
|
||||
|
||||
article, aside, dialog, figcaption, figure, footer, header, hgroup, main, nav, section {
|
||||
display: block;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
||||
font-size: 1rem;
|
||||
font-weight: 400;
|
||||
line-height: 1.5;
|
||||
color: #212529;
|
||||
text-align: left;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
[tabindex="-1"]:focus {
|
||||
outline: 0 !important;
|
||||
}
|
||||
|
||||
hr {
|
||||
box-sizing: content-box;
|
||||
height: 0;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
abbr[title],
|
||||
abbr[data-original-title] {
|
||||
text-decoration: underline;
|
||||
-webkit-text-decoration: underline dotted;
|
||||
text-decoration: underline dotted;
|
||||
cursor: help;
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
address {
|
||||
margin-bottom: 1rem;
|
||||
font-style: normal;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul,
|
||||
dl {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
ol ol,
|
||||
ul ul,
|
||||
ol ul,
|
||||
ul ol {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
dt {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
dd {
|
||||
margin-bottom: .5rem;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
dfn {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: bolder;
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
sub,
|
||||
sup {
|
||||
position: relative;
|
||||
font-size: 75%;
|
||||
line-height: 0;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -.25em;
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -.5em;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #007bff;
|
||||
text-decoration: none;
|
||||
background-color: transparent;
|
||||
-webkit-text-decoration-skip: objects;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #0056b3;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
a:not([href]):not([tabindex]) {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:not([href]):not([tabindex]):hover, a:not([href]):not([tabindex]):focus {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:not([href]):not([tabindex]):focus {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
pre,
|
||||
code,
|
||||
kbd,
|
||||
samp {
|
||||
font-family: monospace, monospace;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
pre {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
overflow: auto;
|
||||
-ms-overflow-style: scrollbar;
|
||||
}
|
||||
|
||||
figure {
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
|
||||
img {
|
||||
vertical-align: middle;
|
||||
border-style: none;
|
||||
}
|
||||
|
||||
svg:not(:root) {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
caption {
|
||||
padding-top: 0.75rem;
|
||||
padding-bottom: 0.75rem;
|
||||
color: #6c757d;
|
||||
text-align: left;
|
||||
caption-side: bottom;
|
||||
}
|
||||
|
||||
th {
|
||||
text-align: inherit;
|
||||
}
|
||||
|
||||
label {
|
||||
display: inline-block;
|
||||
margin-bottom: .5rem;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
button:focus {
|
||||
outline: 1px dotted;
|
||||
outline: 5px auto -webkit-focus-ring-color;
|
||||
}
|
||||
|
||||
input,
|
||||
button,
|
||||
select,
|
||||
optgroup,
|
||||
textarea {
|
||||
margin: 0;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
button,
|
||||
input {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
button,
|
||||
select {
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
button,
|
||||
html [type="button"],
|
||||
[type="reset"],
|
||||
[type="submit"] {
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
|
||||
button::-moz-focus-inner,
|
||||
[type="button"]::-moz-focus-inner,
|
||||
[type="reset"]::-moz-focus-inner,
|
||||
[type="submit"]::-moz-focus-inner {
|
||||
padding: 0;
|
||||
border-style: none;
|
||||
}
|
||||
|
||||
input[type="radio"],
|
||||
input[type="checkbox"] {
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
input[type="date"],
|
||||
input[type="time"],
|
||||
input[type="datetime-local"],
|
||||
input[type="month"] {
|
||||
-webkit-appearance: listbox;
|
||||
}
|
||||
|
||||
textarea {
|
||||
overflow: auto;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
min-width: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
legend {
|
||||
display: block;
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
padding: 0;
|
||||
margin-bottom: .5rem;
|
||||
font-size: 1.5rem;
|
||||
line-height: inherit;
|
||||
color: inherit;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
progress {
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
[type="number"]::-webkit-inner-spin-button,
|
||||
[type="number"]::-webkit-outer-spin-button {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
[type="search"] {
|
||||
outline-offset: -2px;
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
[type="search"]::-webkit-search-cancel-button,
|
||||
[type="search"]::-webkit-search-decoration {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
::-webkit-file-upload-button {
|
||||
font: inherit;
|
||||
-webkit-appearance: button;
|
||||
}
|
||||
|
||||
output {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
summary {
|
||||
display: list-item;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
template {
|
||||
display: none;
|
||||
}
|
||||
|
||||
[hidden] {
|
||||
display: none !important;
|
||||
}
|
||||
/*# sourceMappingURL=bootstrap-reboot.css.map */
|
1
docs/_style/bootstrap/css/bootstrap-reboot.css.map
Normal file
8
docs/_style/bootstrap/css/bootstrap-reboot.min.css
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
/*!
|
||||
* Bootstrap Reboot v4.0.0 (https://getbootstrap.com)
|
||||
* Copyright 2011-2018 The Bootstrap Authors
|
||||
* Copyright 2011-2018 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
|
||||
*/*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:transparent}@-ms-viewport{width:device-width}article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:left;background-color:#fff}[tabindex="-1"]:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}dfn{font-style:italic}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#007bff;text-decoration:none;background-color:transparent;-webkit-text-decoration-skip:objects}a:hover{color:#0056b3;text-decoration:underline}a:not([href]):not([tabindex]){color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto;-ms-overflow-style:scrollbar}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg:not(:root){overflow:hidden}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#6c757d;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important}
|
||||
/*# sourceMappingURL=bootstrap-reboot.min.css.map */
|
1
docs/_style/bootstrap/css/bootstrap-reboot.min.css.map
Normal file
8975
docs/_style/bootstrap/css/bootstrap.css
vendored
Normal file
1
docs/_style/bootstrap/css/bootstrap.css.map
Normal file
7
docs/_style/bootstrap/css/bootstrap.min.css
vendored
Normal file
1
docs/_style/bootstrap/css/bootstrap.min.css.map
Normal file
6328
docs/_style/bootstrap/js/bootstrap.bundle.js
vendored
Normal file
1
docs/_style/bootstrap/js/bootstrap.bundle.js.map
Normal file
7
docs/_style/bootstrap/js/bootstrap.bundle.min.js
vendored
Normal file
1
docs/_style/bootstrap/js/bootstrap.bundle.min.js.map
Normal file
3894
docs/_style/bootstrap/js/bootstrap.js
vendored
Normal file
1
docs/_style/bootstrap/js/bootstrap.js.map
Normal file
7
docs/_style/bootstrap/js/bootstrap.min.js
vendored
Normal file
1
docs/_style/bootstrap/js/bootstrap.min.js.map
Normal file
3
docs/_style/style.css
Normal file
@ -0,0 +1,3 @@
|
||||
#main>ul:nth-child(1) {
|
||||
display: none;
|
||||
}
|
1
docs/guide.md
Normal file
@ -0,0 +1 @@
|
||||
# test
|
62
docs/index.html
Normal file
@ -0,0 +1,62 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Document</title>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
||||
<meta name="description" content="Description">
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||
<link rel="stylesheet" href="//unpkg.com/docsify/lib/themes/vue.css">
|
||||
<link rel="stylesheet" href="//unpkg.com/gitalk/dist/gitalk.css">
|
||||
<link rel="stylesheet" href="_style/style.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<nav>
|
||||
<a href="#/README">HOME</a>
|
||||
</nav>
|
||||
<div id="app"></div>
|
||||
<script>
|
||||
window.$docsify = {
|
||||
name: 'CS-Notes',
|
||||
repo: 'https://github.com/CyC2018/CS-Notes',
|
||||
loadSidebar: false,
|
||||
subMaxLevel: 2,
|
||||
coverpage: true,
|
||||
auto2top: true,
|
||||
autoHeader: true,
|
||||
|
||||
search: {
|
||||
placeholder: '🔍 Type to search ',
|
||||
noData: '😞 No Results! ',
|
||||
// Headline depth, 1 - 6
|
||||
depth: 2,
|
||||
hideOtherSidebarContent: false, // whether or not to hide other sidebar content
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<script src="//unpkg.com/docsify/lib/docsify.min.js"></script>
|
||||
<script src="//unpkg.com/docsify/lib/plugins/gitalk.min.js"></script>
|
||||
<script src="//unpkg.com/gitalk/dist/gitalk.min.js"></script>
|
||||
<script src="//unpkg.com/docsify-copy-code"></script>
|
||||
<script src="//unpkg.com/prismjs/components/prism-java.min.js"></script>
|
||||
<script src="//unpkg.com/prismjs/components/prism-c.min.js"></script>
|
||||
<script src="//unpkg.com/prismjs/components/prism-bash.min.js"></script>
|
||||
<script src="//unpkg.com/docsify/lib/plugins/zoom-image.min.js"></script>
|
||||
<script src="//unpkg.com/docsify/lib/plugins/emoji.min.js"></script>
|
||||
<script src="//unpkg.com/docsify/lib/plugins/search.min.js"></script>
|
||||
<script src="//unpkg.com/docsify-pagination/dist/docsify-pagination.min.js"></script>
|
||||
<script>
|
||||
const gitalk = new Gitalk({
|
||||
clientID: 'c6c02367e36ca6e2bb2d',
|
||||
clientSecret: '31a2700e3315b21c5e9f2e887709d8cf21f9ff8f',
|
||||
repo: 'CS-Notes',
|
||||
owner: 'CyC2018',
|
||||
admin: ['CyC2018'],
|
||||
// distractionFreeMode: false
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
@ -8,7 +8,7 @@
|
||||
<!-- GFM-TOC -->
|
||||
|
||||
|
||||
<div align="center"> <img src="../pics//011f3ef6-d824-4d43-8b2c-36dab8eaaa72-1.png"/> </div><br>
|
||||
<div align="center"> <img src="pics/011f3ef6-d824-4d43-8b2c-36dab8eaaa72-1.png"/> </div><br>
|
||||
|
||||
# 一、解决的问题
|
||||
|
||||
@ -20,9 +20,9 @@ Docker 主要解决环境配置问题,它是一种虚拟化技术,对进程
|
||||
|
||||
虚拟机也是一种虚拟化技术,它与 Docker 最大的区别在于它是通过模拟硬件,并在硬件上安装操作系统来实现。
|
||||
|
||||
<div align="center"> <img src="../pics//71f61bc3-582d-4c27-8bdd-dc7fb135bf8f.png"/> </div><br>
|
||||
<div align="center"> <img src="pics/71f61bc3-582d-4c27-8bdd-dc7fb135bf8f.png"/> </div><br>
|
||||
|
||||
<div align="center"> <img src="../pics//7e873b60-44dc-4911-b080-defd5b8f0b49.png"/> </div><br>
|
||||
<div align="center"> <img src="pics/7e873b60-44dc-4911-b080-defd5b8f0b49.png"/> </div><br>
|
||||
|
||||
## 启动速度
|
||||
|
||||
@ -76,7 +76,7 @@ Docker 轻量级的特点使得它很适合用于部署、维护、组合微服
|
||||
|
||||
构建容器时,通过在镜像的基础上添加一个可写层(writable layer),用来保存着容器运行过程中的修改。
|
||||
|
||||
<div align="center"> <img src="../pics//docker-filesystems-busyboxrw.png"/> </div><br>
|
||||
<div align="center"> <img src="pics/docker-filesystems-busyboxrw.png"/> </div><br>
|
||||
|
||||
# 参考资料
|
||||
|
@ -34,49 +34,49 @@ Github 就是一个中心服务器。
|
||||
|
||||
# 工作流
|
||||
|
||||
<div align="center"> <img src="../pics//a1198642-9159-4d88-8aec-c3b04e7a2563.jpg"/> </div><br>
|
||||
<div align="center"> <img src="pics/a1198642-9159-4d88-8aec-c3b04e7a2563.jpg"/> </div><br>
|
||||
|
||||
新建一个仓库之后,当前目录就成为了工作区,工作区下有一个隐藏目录 .git,它属于 Git 的版本库。
|
||||
|
||||
Git 版本库有一个称为 stage 的暂存区,还有自动创建的 master 分支以及指向分支的 HEAD 指针。
|
||||
|
||||
<div align="center"> <img src="../pics//46f66e88-e65a-4ad0-a060-3c63fe22947c.png"/> </div><br>
|
||||
<div align="center"> <img src="pics/46f66e88-e65a-4ad0-a060-3c63fe22947c.png"/> </div><br>
|
||||
|
||||
- git add files 把文件的修改添加到暂存区
|
||||
- git commit 把暂存区的修改提交到当前分支,提交之后暂存区就被清空了
|
||||
- git reset -- files 使用当前分支上的修改覆盖暂缓区,用来撤销最后一次 git add files
|
||||
- git reset -- files 使用当前分支上的修改覆盖暂存区,用来撤销最后一次 git add files
|
||||
- git checkout -- files 使用暂存区的修改覆盖工作目录,用来撤销本地修改
|
||||
|
||||
<div align="center"> <img src="../pics//17976404-95f5-480e-9cb4-250e6aa1d55f.png"/> </div><br>
|
||||
<div align="center"> <img src="pics/17976404-95f5-480e-9cb4-250e6aa1d55f.png"/> </div><br>
|
||||
|
||||
可以跳过暂存区域直接从分支中取出修改,或者直接提交修改到分支中。
|
||||
|
||||
- git commit -a 直接把所有文件的修改添加到暂缓区然后执行提交
|
||||
- git commit -a 直接把所有文件的修改添加到暂存区然后执行提交
|
||||
- git checkout HEAD -- files 取出最后一次修改,可以用来进行回滚操作
|
||||
|
||||
# 分支实现
|
||||
|
||||
使用指针将每个提交连接成一条时间线,HEAD 指针指向当前分支指针。
|
||||
|
||||
<div align="center"> <img src="../pics//fb546e12-e1fb-4b72-a1fb-8a7f5000dce6.jpg"/> </div><br>
|
||||
<div align="center"> <img src="pics/fb546e12-e1fb-4b72-a1fb-8a7f5000dce6.jpg"/> </div><br>
|
||||
|
||||
新建分支是新建一个指针指向时间线的最后一个节点,并让 HEAD 指针指向新分支表示新分支成为当前分支。
|
||||
|
||||
<div align="center"> <img src="../pics//bc775758-89ab-4805-9f9c-78b8739cf780.jpg"/> </div><br>
|
||||
<div align="center"> <img src="pics/bc775758-89ab-4805-9f9c-78b8739cf780.jpg"/> </div><br>
|
||||
|
||||
每次提交只会让当前分支指针向前移动,而其它分支指针不会移动。
|
||||
|
||||
<div align="center"> <img src="../pics//5292faa6-0141-4638-bf0f-bb95b081dcba.jpg"/> </div><br>
|
||||
<div align="center"> <img src="pics/5292faa6-0141-4638-bf0f-bb95b081dcba.jpg"/> </div><br>
|
||||
|
||||
合并分支也只需要改变指针即可。
|
||||
|
||||
<div align="center"> <img src="../pics//1164a71f-413d-494a-9cc8-679fb6a2613d.jpg"/> </div><br>
|
||||
<div align="center"> <img src="pics/1164a71f-413d-494a-9cc8-679fb6a2613d.jpg"/> </div><br>
|
||||
|
||||
# 冲突
|
||||
|
||||
当两个分支都对同一个文件的同一行进行了修改,在分支合并时就会产生冲突。
|
||||
|
||||
<div align="center"> <img src="../pics//58e57a21-6b6b-40b6-af85-956dd4e0f55a.jpg"/> </div><br>
|
||||
<div align="center"> <img src="pics/58e57a21-6b6b-40b6-af85-956dd4e0f55a.jpg"/> </div><br>
|
||||
|
||||
Git 会使用 <<<<<<< ,======= ,>>>>>>> 标记出不同分支的内容,只需要把不同分支中冲突部分修改成一样就能解决冲突。
|
||||
|
||||
@ -98,7 +98,7 @@ Creating a new branch is quick AND simple.
|
||||
$ git merge --no-ff -m "merge with no-ff" dev
|
||||
```
|
||||
|
||||
<div align="center"> <img src="../pics//dd78a1fe-1ff3-4bcf-a56f-8c003995beb6.jpg"/> </div><br>
|
||||
<div align="center"> <img src="pics/dd78a1fe-1ff3-4bcf-a56f-8c003995beb6.jpg"/> </div><br>
|
||||
|
||||
# 分支管理策略
|
||||
|
||||
@ -106,7 +106,7 @@ master 分支应该是非常稳定的,只用来发布新版本;
|
||||
|
||||
日常开发在开发分支 dev 上进行。
|
||||
|
||||
<div align="center"> <img src="../pics//245fd2fb-209c-4ad5-bc5e-eb5664966a0e.jpg"/> </div><br>
|
||||
<div align="center"> <img src="pics/245fd2fb-209c-4ad5-bc5e-eb5664966a0e.jpg"/> </div><br>
|
||||
|
||||
# 储藏(Stashing)
|
||||
|
||||
@ -146,7 +146,7 @@ $ ssh-keygen -t rsa -C "youremail@example.com"
|
||||
|
||||
# Git 命令一览
|
||||
|
||||
<div align="center"> <img src="../pics//7a29acce-f243-4914-9f00-f2988c528412.jpg"/> </div><br>
|
||||
<div align="center"> <img src="pics/7a29acce-f243-4914-9f00-f2988c528412.jpg"/> </div><br>
|
||||
|
||||
比较详细的地址:http://www.cheat-sheets.org/saved-copy/git-cheat-sheet.pdf
|
||||
|
@ -66,17 +66,17 @@ URI 包含 URL 和 URN,目前 WEB 只有 URL 比较流行,所以见到的基
|
||||
- URL(Uniform Resource Locator,统一资源定位符)
|
||||
- URN(Uniform Resource Name,统一资源名称)
|
||||
|
||||
<div align="center"> <img src="../pics//urlnuri.jpg" width="600"/> </div><br>
|
||||
<div align="center"> <img src="pics/urlnuri.jpg" width="600"/> </div><br>
|
||||
|
||||
## 请求和响应报文
|
||||
|
||||
### 1. 请求报文
|
||||
|
||||
<div align="center"> <img src="../pics//HTTP_RequestMessageExample.png" width=""/> </div><br>
|
||||
<div align="center"> <img src="pics/HTTP_RequestMessageExample.png" width=""/> </div><br>
|
||||
|
||||
### 2. 响应报文
|
||||
|
||||
<div align="center"> <img src="../pics//HTTP_ResponseMessageExample.png" width=""/> </div><br>
|
||||
<div align="center"> <img src="pics/HTTP_ResponseMessageExample.png" width=""/> </div><br>
|
||||
|
||||
# 二、HTTP 方法
|
||||
|
||||
@ -163,7 +163,7 @@ DELETE /file.html HTTP/1.1
|
||||
CONNECT www.example.com:443 HTTP/1.1
|
||||
```
|
||||
|
||||
<div align="center"> <img src="../pics//dc00f70e-c5c8-4d20-baf1-2d70014a97e3.jpg" width=""/> </div><br>
|
||||
<div align="center"> <img src="pics/dc00f70e-c5c8-4d20-baf1-2d70014a97e3.jpg" width=""/> </div><br>
|
||||
|
||||
## TRACE
|
||||
|
||||
@ -305,7 +305,7 @@ CONNECT www.example.com:443 HTTP/1.1
|
||||
|
||||
## 连接管理
|
||||
|
||||
<div align="center"> <img src="../pics//HTTP1_x_Connections.png" width="800"/> </div><br>
|
||||
<div align="center"> <img src="pics/HTTP1_x_Connections.png" width="800"/> </div><br>
|
||||
|
||||
### 1. 短连接与长连接
|
||||
|
||||
@ -634,11 +634,11 @@ HTTP/1.1 使用虚拟主机技术,使得一台服务器拥有多个域名,
|
||||
|
||||
- 用户察觉得到正向代理的存在。
|
||||
|
||||
<div align="center"> <img src="../pics//a314bb79-5b18-4e63-a976-3448bffa6f1b.png" width=""/> </div><br>
|
||||
<div align="center"> <img src="pics/a314bb79-5b18-4e63-a976-3448bffa6f1b.png" width=""/> </div><br>
|
||||
|
||||
- 而反向代理一般位于内部网络中,用户察觉不到。
|
||||
|
||||
<div align="center"> <img src="../pics//2d09a847-b854-439c-9198-b29c65810944.png" width=""/> </div><br>
|
||||
<div align="center"> <img src="pics/2d09a847-b854-439c-9198-b29c65810944.png" width=""/> </div><br>
|
||||
|
||||
### 2. 网关
|
||||
|
||||
@ -660,7 +660,7 @@ HTTPs 并不是新协议,而是让 HTTP 先和 SSL(Secure Sockets Layer)
|
||||
|
||||
通过使用 SSL,HTTPs 具有了加密(防窃听)、认证(防伪装)和完整性保护(防篡改)。
|
||||
|
||||
<div align="center"> <img src="../pics//ssl-offloading.jpg" width="700"/> </div><br>
|
||||
<div align="center"> <img src="pics/ssl-offloading.jpg" width="700"/> </div><br>
|
||||
|
||||
## 加密
|
||||
|
||||
@ -671,7 +671,7 @@ HTTPs 并不是新协议,而是让 HTTP 先和 SSL(Secure Sockets Layer)
|
||||
- 优点:运算速度快;
|
||||
- 缺点:无法安全地将密钥传输给通信方。
|
||||
|
||||
<div align="center"> <img src="../pics//7fffa4b8-b36d-471f-ad0c-a88ee763bb76.png" width="600"/> </div><br>
|
||||
<div align="center"> <img src="pics/7fffa4b8-b36d-471f-ad0c-a88ee763bb76.png" width="600"/> </div><br>
|
||||
|
||||
### 2.非对称密钥加密
|
||||
|
||||
@ -684,13 +684,13 @@ HTTPs 并不是新协议,而是让 HTTP 先和 SSL(Secure Sockets Layer)
|
||||
- 优点:可以更安全地将公开密钥传输给通信发送方;
|
||||
- 缺点:运算速度慢。
|
||||
|
||||
<div align="center"> <img src="../pics//39ccb299-ee99-4dd1-b8b4-2f9ec9495cb4.png" width="600"/> </div><br>
|
||||
<div align="center"> <img src="pics/39ccb299-ee99-4dd1-b8b4-2f9ec9495cb4.png" width="600"/> </div><br>
|
||||
|
||||
### 3. HTTPs 采用的加密方式
|
||||
|
||||
HTTPs 采用混合的加密机制,使用非对称密钥加密用于传输对称密钥来保证传输过程的安全性,之后使用对称密钥加密进行通信来保证通信过程的效率。(下图中的 Session Key 就是对称密钥)
|
||||
|
||||
<div align="center"> <img src="../pics//How-HTTPS-Works.png" width="600"/> </div><br>
|
||||
<div align="center"> <img src="pics/How-HTTPS-Works.png" width="600"/> </div><br>
|
||||
|
||||
## 认证
|
||||
|
||||
@ -704,7 +704,7 @@ HTTPs 采用混合的加密机制,使用非对称密钥加密用于传输对
|
||||
|
||||
通信开始时,客户端需要使用服务器的公开密钥将自己的私有密钥传输给服务器,之后再进行对称密钥加密。
|
||||
|
||||
<div align="center"> <img src="../pics//2017-06-11-ca.png" width=""/> </div><br>
|
||||
<div align="center"> <img src="pics/2017-06-11-ca.png" width=""/> </div><br>
|
||||
|
||||
## 完整性保护
|
||||
|
||||
@ -732,7 +732,7 @@ HTTP/1.x 实现简单是以牺牲性能为代价的:
|
||||
|
||||
HTTP/2.0 将报文分成 HEADERS 帧和 DATA 帧,它们都是二进制格式的。
|
||||
|
||||
<div align="center"> <img src="../pics//86e6a91d-a285-447a-9345-c5484b8d0c47.png" width="400"/> </div><br>
|
||||
<div align="center"> <img src="pics/86e6a91d-a285-447a-9345-c5484b8d0c47.png" width="400"/> </div><br>
|
||||
|
||||
在通信过程中,只会有一个 TCP 连接存在,它承载了任意数量的双向数据流(Stream)。
|
||||
|
||||
@ -740,13 +740,13 @@ HTTP/2.0 将报文分成 HEADERS 帧和 DATA 帧,它们都是二进制格式
|
||||
- 消息(Message)是与逻辑请求或响应对应的完整的一系列帧。
|
||||
- 帧(Frame)是最小的通信单位,来自不同数据流的帧可以交错发送,然后再根据每个帧头的数据流标识符重新组装。
|
||||
|
||||
<div align="center"> <img src="../pics//af198da1-2480-4043-b07f-a3b91a88b815.png" width="600"/> </div><br>
|
||||
<div align="center"> <img src="pics/af198da1-2480-4043-b07f-a3b91a88b815.png" width="600"/> </div><br>
|
||||
|
||||
## 服务端推送
|
||||
|
||||
HTTP/2.0 在客户端请求一个资源时,会把相关的资源一起发送给客户端,客户端就不需要再次发起请求了。例如客户端请求 page.html 页面,服务端就把 script.js 和 style.css 等与之相关的资源一起发给客户端。
|
||||
|
||||
<div align="center"> <img src="../pics//e3f1657c-80fc-4dfa-9643-bf51abd201c6.png" width="800"/> </div><br>
|
||||
<div align="center"> <img src="pics/e3f1657c-80fc-4dfa-9643-bf51abd201c6.png" width="800"/> </div><br>
|
||||
|
||||
## 首部压缩
|
||||
|
||||
@ -756,7 +756,7 @@ HTTP/2.0 要求客户端和服务器同时维护和更新一个包含之前见
|
||||
|
||||
不仅如此,HTTP/2.0 也使用 Huffman 编码对首部字段进行压缩。
|
||||
|
||||
<div align="center"> <img src="../pics//_u4E0B_u8F7D.png" width="600"/> </div><br>
|
||||
<div align="center"> <img src="pics/_u4E0B_u8F7D.png" width="600"/> </div><br>
|
||||
|
||||
# 八、HTTP/1.1 新特性
|
||||
|
@ -63,6 +63,8 @@ public static void listAllFiles(File dir) {
|
||||
}
|
||||
```
|
||||
|
||||
从 Java7 开始,可以使用 Paths 和 Files 代替 File。
|
||||
|
||||
# 三、字节操作
|
||||
|
||||
## 实现文件复制
|
||||
@ -95,7 +97,7 @@ Java I/O 使用了装饰者模式来实现。以 InputStream 为例,
|
||||
- FileInputStream 是 InputStream 的子类,属于具体组件,提供了字节流的输入操作;
|
||||
- FilterInputStream 属于抽象装饰者,装饰者用于装饰组件,为组件提供额外的功能。例如 BufferedInputStream 为 FileInputStream 提供缓存的功能。
|
||||
|
||||
<div align="center"> <img src="../pics//DP-Decorator-java.io.png" width="500"/> </div><br>
|
||||
<div align="center"> <img src="pics/DP-Decorator-java.io.png" width="500"/> </div><br>
|
||||
|
||||
实例化一个具有缓存功能的字节流对象时,只需要在 FileInputStream 对象上再套一层 BufferedInputStream 对象即可。
|
||||
|
||||
@ -120,7 +122,7 @@ DataInputStream 装饰者提供了对更多数据类型进行输入的操作,
|
||||
|
||||
UTF-16be 中的 be 指的是 Big Endian,也就是大端。相应地也有 UTF-16le,le 指的是 Little Endian,也就是小端。
|
||||
|
||||
Java 使用双字节编码 UTF-16be,这不是指 Java 只支持这一种编码方式,而是说 char 这种类型使用 UTF-16be 进行编码。char 类型占 16 位,也就是两个字节,Java 使用这种双字节编码是为了让一个中文或者一个英文都能使用一个 char 来存储。
|
||||
Java 的内存编码使用双字节编码 UTF-16be,这不是指 Java 只支持这一种编码方式,而是说 char 这种类型使用 UTF-16be 进行编码。char 类型占 16 位,也就是两个字节,Java 使用这种双字节编码是为了让一个中文或者一个英文都能使用一个 char 来存储。
|
||||
|
||||
## String 的编码方式
|
||||
|
||||
@ -275,7 +277,7 @@ public static void main(String[] args) throws IOException {
|
||||
- Socket:客户端类
|
||||
- 服务器和客户端通过 InputStream 和 OutputStream 进行输入输出。
|
||||
|
||||
<div align="center"> <img src="../pics//ClienteServidorSockets1521731145260.jpg"/> </div><br>
|
||||
<div align="center"> <img src="pics/ClienteServidorSockets1521731145260.jpg"/> </div><br>
|
||||
|
||||
## Datagram
|
||||
|
||||
@ -337,23 +339,23 @@ I/O 包和 NIO 已经很好地集成了,java.io.\* 已经以 NIO 为基础重
|
||||
|
||||
① 新建一个大小为 8 个字节的缓冲区,此时 position 为 0,而 limit = capacity = 8。capacity 变量不会改变,下面的讨论会忽略它。
|
||||
|
||||
<div align="center"> <img src="../pics//1bea398f-17a7-4f67-a90b-9e2d243eaa9a.png"/> </div><br>
|
||||
<div align="center"> <img src="pics/1bea398f-17a7-4f67-a90b-9e2d243eaa9a.png"/> </div><br>
|
||||
|
||||
② 从输入通道中读取 5 个字节数据写入缓冲区中,此时 position 为 5,limit 保持不变。
|
||||
|
||||
<div align="center"> <img src="../pics//80804f52-8815-4096-b506-48eef3eed5c6.png"/> </div><br>
|
||||
<div align="center"> <img src="pics/80804f52-8815-4096-b506-48eef3eed5c6.png"/> </div><br>
|
||||
|
||||
③ 在将缓冲区的数据写到输出通道之前,需要先调用 flip() 方法,这个方法将 limit 设置为当前 position,并将 position 设置为 0。
|
||||
|
||||
<div align="center"> <img src="../pics//952e06bd-5a65-4cab-82e4-dd1536462f38.png"/> </div><br>
|
||||
<div align="center"> <img src="pics/952e06bd-5a65-4cab-82e4-dd1536462f38.png"/> </div><br>
|
||||
|
||||
④ 从缓冲区中取 4 个字节到输出缓冲中,此时 position 设为 4。
|
||||
|
||||
<div align="center"> <img src="../pics//b5bdcbe2-b958-4aef-9151-6ad963cb28b4.png"/> </div><br>
|
||||
<div align="center"> <img src="pics/b5bdcbe2-b958-4aef-9151-6ad963cb28b4.png"/> </div><br>
|
||||
|
||||
⑤ 最后需要调用 clear() 方法来清空缓冲区,此时 position 和 limit 都被设置为最初位置。
|
||||
|
||||
<div align="center"> <img src="../pics//67bf5487-c45d-49b6-b9c0-a058d8c68902.png"/> </div><br>
|
||||
<div align="center"> <img src="pics/67bf5487-c45d-49b6-b9c0-a058d8c68902.png"/> </div><br>
|
||||
|
||||
## 文件 NIO 实例
|
||||
|
||||
@ -411,7 +413,7 @@ NIO 实现了 IO 多路复用中的 Reactor 模型,一个线程 Thread 使用
|
||||
|
||||
应该注意的是,只有套接字 Channel 才能配置为非阻塞,而 FileChannel 不能,为 FileChannel 配置非阻塞也没有意义。
|
||||
|
||||
<div align="center"> <img src="../pics//4d930e22-f493-49ae-8dff-ea21cd6895dc.png"/> </div><br>
|
||||
<div align="center"> <img src="pics/4d930e22-f493-49ae-8dff-ea21cd6895dc.png"/> </div><br>
|
||||
|
||||
### 1. 创建选择器
|
||||
|
||||
@ -611,7 +613,7 @@ NIO 与普通 I/O 的区别主要有以下两点:
|
||||
- [Java NIO Tutorial](http://tutorials.jenkov.com/java-nio/index.html)
|
||||
- [Java NIO 浅析](https://tech.meituan.com/nio.html)
|
||||
- [IBM: 深入分析 Java I/O 的工作机制](https://www.ibm.com/developerworks/cn/java/j-lo-javaio/index.html)
|
||||
- [IBM: 深入分析 Java 中的中文编码问题](https://www.ibm.com/developerworks/cn/java/j-lo-chinesecoding/index.htm)
|
||||
- [IBM: 深入分析 Java 中的中文编码问题](https://www.ibm.com/developerworks/cn/java/j-lo-chinesecoding/index.html)
|
||||
- [IBM: Java 序列化的高级认识](https://www.ibm.com/developerworks/cn/java/j-lo-serial/index.html)
|
||||
- [NIO 与传统 IO 的区别](http://blog.csdn.net/shimiso/article/details/24990499)
|
||||
- [Decorator Design Pattern](http://stg-tud.github.io/sedc/Lecture/ws13-14/5.3-Decorator.html#mode=document)
|
@ -167,7 +167,7 @@ public final class String
|
||||
|
||||
如果一个 String 对象已经被创建过了,那么就会从 String Pool 中取得引用。只有 String 是不可变的,才可能使用 String Pool。
|
||||
|
||||
<div align="center"> <img src="../pics//f76067a5-7d5f-4135-9549-8199c77d8f1c.jpg" width=""/> </div><br>
|
||||
<div align="center"> <img src="pics/f76067a5-7d5f-4135-9549-8199c77d8f1c.jpg" width=""/> </div><br>
|
||||
|
||||
**3. 安全性**
|
||||
|
||||
@ -1209,19 +1209,21 @@ Class 和 java.lang.reflect 一起对反射提供了支持,java.lang.reflect
|
||||
- **Method** :可以使用 invoke() 方法调用与 Method 对象关联的方法;
|
||||
- **Constructor** :可以用 Constructor 创建新的对象。
|
||||
|
||||
**Advantages of Using Reflection:**
|
||||
**反射的优点:**
|
||||
|
||||
- **Extensibility Features** : An application may make use of external, user-defined classes by creating instances of extensibility objects using their fully-qualified names.
|
||||
- **Class Browsers and Visual Development Environments** : A class browser needs to be able to enumerate the members of classes. Visual development environments can benefit from making use of type information available in reflection to aid the developer in writing correct code.
|
||||
- **Debuggers and Test Tools** : Debuggers need to be able to examine private members on classes. Test harnesses can make use of reflection to systematically call a discoverable set APIs defined on a class, to insure a high level of code coverage in a test suite.
|
||||
* **可扩展性** :应用程序可以利用全限定名创建可扩展对象的实例,来使用来自外部的用户自定义类。
|
||||
* **类浏览器和可视化开发环境** :一个类浏览器需要可以枚举类的成员。可视化开发环境(如 IDE)可以从利用反射中可用的类型信息中受益,以帮助程序员编写正确的代码。
|
||||
* **调试器和测试工具** : 调试器需要能够检查一个类里的私有成员。测试工具可以利用反射来自动地调用类里定义的可被发现的 API 定义,以确保一组测试中有较高的代码覆盖率。
|
||||
|
||||
**Drawbacks of Reflection:**
|
||||
**反射的缺点:**
|
||||
|
||||
Reflection is powerful, but should not be used indiscriminately. If it is possible to perform an operation without using reflection, then it is preferable to avoid using it. The following concerns should be kept in mind when accessing code via reflection.
|
||||
尽管反射非常强大,但也不能滥用。如果一个功能可以不用反射完成,那么最好就不用。在我们使用反射技术时,下面几条内容应该牢记于心。
|
||||
|
||||
- **Performance Overhead** : Because reflection involves types that are dynamically resolved, certain Java virtual machine optimizations can not be performed. Consequently, reflective operations have slower performance than their non-reflective counterparts, and should be avoided in sections of code which are called frequently in performance-sensitive applications.
|
||||
- **Security Restrictions** : Reflection requires a runtime permission which may not be present when running under a security manager. This is in an important consideration for code which has to run in a restricted security context, such as in an Applet.
|
||||
- **Exposure of Internals** :Since reflection allows code to perform operations that would be illegal in non-reflective code, such as accessing private fields and methods, the use of reflection can result in unexpected side-effects, which may render code dysfunctional and may destroy portability. Reflective code breaks abstractions and therefore may change behavior with upgrades of the platform.
|
||||
* **性能开销** :反射涉及了动态类型的解析,所以 JVM 无法对这些代码进行优化。因此,反射操作的效率要比那些非反射操作低得多。我们应该避免在经常被执行的代码或对性能要求很高的程序中使用反射。
|
||||
|
||||
* **安全限制** :使用反射技术要求程序必须在一个没有安全限制的环境中运行。如果一个程序必须在有安全限制的环境中运行,如 Applet,那么这就是个问题了。
|
||||
|
||||
* **内部暴露** :由于反射允许代码执行一些在正常情况下不被允许的操作(比如访问私有的属性和方法),所以使用反射可能会导致意料之外的副作用,这可能导致代码功能失调并破坏可移植性。反射代码破坏了抽象性,因此当平台发生改变的时候,代码的行为就有可能也随着变化。
|
||||
|
||||
|
||||
- [Trail: The Reflection API](https://docs.oracle.com/javase/tutorial/reflect/index.html)
|
||||
@ -1234,7 +1236,7 @@ Throwable 可以用来表示任何可以作为异常抛出的类,分为两种
|
||||
- **受检异常** :需要用 try...catch... 语句捕获并进行处理,并且可以从异常中恢复;
|
||||
- **非受检异常** :是程序运行时错误,例如除 0 会引发 Arithmetic Exception,此时程序崩溃并且无法恢复。
|
||||
|
||||
<div align="center"> <img src="../pics//PPjwP.png" width="600"/> </div><br>
|
||||
<div align="center"> <img src="pics/PPjwP.png" width="600"/> </div><br>
|
||||
|
||||
- [Java 入门之异常处理](https://www.tianmaying.com/tutorial/Java-Exception)
|
||||
- [Java 异常的面试问题及答案 -Part 1](http://www.importnew.com/7383.html)
|
@ -25,7 +25,7 @@
|
||||
|
||||
## Collection
|
||||
|
||||
<div align="center"> <img src="../pics//VP6n3i8W48Ptde8NQ9_0eSR5eOD6uqx.png"/> </div><br>
|
||||
<div align="center"> <img src="pics/VP6n3i8W48Ptde8NQ9_0eSR5eOD6uqx.png"/> </div><br>
|
||||
|
||||
### 1. Set
|
||||
|
||||
@ -51,7 +51,7 @@
|
||||
|
||||
## Map
|
||||
|
||||
<div align="center"> <img src="../pics//SoWkIImgAStDuUBAp2j9BKfBJ4vLy4q.png"/> </div><br>
|
||||
<div align="center"> <img src="pics/SoWkIImgAStDuUBAp2j9BKfBJ4vLy4q.png"/> </div><br>
|
||||
|
||||
- TreeMap:基于红黑树实现。
|
||||
|
||||
@ -66,9 +66,9 @@
|
||||
|
||||
## 迭代器模式
|
||||
|
||||
<div align="center"> <img src="../pics//SoWkIImgAStDuUBAp2j9BKfBJ4vLy0G.png"/> </div><br>
|
||||
<div align="center"> <img src="pics/SoWkIImgAStDuUBAp2j9BKfBJ4vLy0G.png"/> </div><br>
|
||||
|
||||
Collection 实现了 Iterable 接口,其中的 iterator() 方法能够产生一个 Iterator 对象,通过这个对象就可以迭代遍历 Collection 中的元素。
|
||||
Collection 继承了 Iterable 接口,其中的 iterator() 方法能够产生一个 Iterator 对象,通过这个对象就可以迭代遍历 Collection 中的元素。
|
||||
|
||||
从 JDK 1.5 之后可以使用 foreach 方法来遍历实现了 Iterable 接口的聚合对象。
|
||||
|
||||
@ -387,7 +387,7 @@ transient Node<E> first;
|
||||
transient Node<E> last;
|
||||
```
|
||||
|
||||
<div align="center"> <img src="../pics//49495c95-52e5-4c9a-b27b-92cf235ff5ec.png" width="500"/> </div><br>
|
||||
<div align="center"> <img src="pics/49495c95-52e5-4c9a-b27b-92cf235ff5ec.png" width="500"/> </div><br>
|
||||
|
||||
### 2. 与 ArrayList 的比较
|
||||
|
||||
@ -409,7 +409,7 @@ transient Entry[] table;
|
||||
|
||||
Entry 存储着键值对。它包含了四个字段,从 next 字段我们可以看出 Entry 是一个链表。即数组中的每个位置被当成一个桶,一个桶存放一个链表。HashMap 使用拉链法来解决冲突,同一个链表中存放哈希值相同的 Entry。
|
||||
|
||||
<div align="center"> <img src="../pics//8fe838e3-ef77-4f63-bf45-417b6bc5c6bb.png" width="600"/> </div><br>
|
||||
<div align="center"> <img src="pics/8fe838e3-ef77-4f63-bf45-417b6bc5c6bb.png" width="600"/> </div><br>
|
||||
|
||||
```java
|
||||
static class Entry<K,V> implements Map.Entry<K,V> {
|
||||
@ -485,7 +485,7 @@ map.put("K3", "V3");
|
||||
- 计算键值对所在的桶;
|
||||
- 在链表上顺序查找,时间复杂度显然和链表的长度成正比。
|
||||
|
||||
<div align="center"> <img src="../pics//49d6de7b-0d0d-425c-9e49-a1559dc23b10.png" width="600"/> </div><br>
|
||||
<div align="center"> <img src="pics/49d6de7b-0d0d-425c-9e49-a1559dc23b10.png" width="600"/> </div><br>
|
||||
|
||||
### 3. put 操作
|
||||
|
||||
@ -646,8 +646,8 @@ static int indexFor(int h, int length) {
|
||||
| 参数 | 含义 |
|
||||
| :--: | :-- |
|
||||
| capacity | table 的容量大小,默认为 16。需要注意的是 capacity 必须保证为 2 的 n 次方。|
|
||||
| size | table 的实际使用量。 |
|
||||
| threshold | size 的临界值,size 必须小于 threshold,如果大于等于,就必须进行扩容操作。 |
|
||||
| size | 键值对数量。 |
|
||||
| threshold | size 的临界值,当 size 大于等于 threshold 就必须进行扩容操作。 |
|
||||
| loadFactor | 装载因子,table 能够使用的比例,threshold = capacity * loadFactor。|
|
||||
|
||||
```java
|
||||
@ -727,7 +727,7 @@ new capacity : 00100000
|
||||
|
||||
对于一个 Key,
|
||||
|
||||
- 它的哈希值如果在第 6 位上为 0,那么取模得到的结果和之前一样;
|
||||
- 它的哈希值如果在第 5 位上为 0,那么取模得到的结果和之前一样;
|
||||
- 如果为 1,那么得到的结果为原来的结果 +16。
|
||||
|
||||
### 7. 计算数组容量
|
||||
@ -821,7 +821,7 @@ final Segment<K,V>[] segments;
|
||||
static final int DEFAULT_CONCURRENCY_LEVEL = 16;
|
||||
```
|
||||
|
||||
<div align="center"> <img src="../pics//3fdfc89d-719e-4d93-b518-29fa612b3b18.png"/> </div><br>
|
||||
<div align="center"> <img src="pics/3fdfc89d-719e-4d93-b518-29fa612b3b18.png"/> </div><br>
|
||||
|
||||
### 2. size 操作
|
||||
|
@ -61,7 +61,7 @@
|
||||
|
||||
# 一、线程状态转换
|
||||
|
||||
<div align="center"> <img src="../pics//ace830df-9919-48ca-91b5-60b193f593d2.png" width=""/> </div><br>
|
||||
<div align="center"> <img src="pics/ace830df-9919-48ca-91b5-60b193f593d2.png" width=""/> </div><br>
|
||||
|
||||
## 新建(New)
|
||||
|
||||
@ -632,7 +632,7 @@ B
|
||||
|
||||
它们都属于 Object 的一部分,而不属于 Thread。
|
||||
|
||||
只能用在同步方法或者同步控制块中使用,否则会在运行时抛出 IllegalMonitorStateExeception。
|
||||
只能用在同步方法或者同步控制块中使用,否则会在运行时抛出 IllegalMonitorStateException。
|
||||
|
||||
使用 wait() 挂起期间,线程会释放锁。这是因为,如果没有释放锁,那么其它线程就无法进入对象的同步方法或者同步控制块中,那么就无法执行 notify() 或者 notifyAll() 来唤醒挂起的线程,造成死锁。
|
||||
|
||||
@ -736,7 +736,7 @@ java.util.concurrent(J.U.C)大大提高了并发性能,AQS 被认为是 J.
|
||||
|
||||
维护了一个计数器 cnt,每次调用 countDown() 方法会让计数器的值减 1,减到 0 的时候,那些因为调用 await() 方法而在等待的线程就会被唤醒。
|
||||
|
||||
<div align="center"> <img src="../pics//CountdownLatch.png" width=""/> </div><br>
|
||||
<div align="center"> <img src="pics/CountdownLatch.png" width=""/> </div><br>
|
||||
|
||||
```java
|
||||
public class CountdownLatchExample {
|
||||
@ -785,7 +785,7 @@ public CyclicBarrier(int parties) {
|
||||
}
|
||||
```
|
||||
|
||||
<div align="center"> <img src="../pics//CyclicBarrier.png" width=""/> </div><br>
|
||||
<div align="center"> <img src="pics/CyclicBarrier.png" width=""/> </div><br>
|
||||
|
||||
```java
|
||||
public class CyclicBarrierExample {
|
||||
@ -818,7 +818,7 @@ before..before..before..before..before..before..before..before..before..before..
|
||||
|
||||
Semaphore 类似于操作系统中的信号量,可以控制对互斥资源的访问线程数。
|
||||
|
||||
<div align="center"> <img src="../pics//Semaphore.png" width=""/> </div><br>
|
||||
<div align="center"> <img src="pics/Semaphore.png" width=""/> </div><br>
|
||||
|
||||
以下代码模拟了对某个服务的并发请求,每次只能有 3 个客户端同时访问,请求总数为 10。
|
||||
|
||||
@ -1024,7 +1024,7 @@ public class ForkJoinPool extends AbstractExecutorService
|
||||
|
||||
ForkJoinPool 实现了工作窃取算法来提高 CPU 的利用率。每个线程都维护了一个双端队列,用来存储需要执行的任务。工作窃取算法允许空闲的线程从其它线程的双端队列中窃取一个任务来执行。窃取的任务必须是最晚的任务,避免和队列所属线程发生竞争。例如下图中,Thread2 从 Thread1 的队列中拿出最晚的 Task1 任务,Thread1 会拿出 Task2 来执行,这样就避免发生竞争。但是如果队列中只有一个任务时还是会发生竞争。
|
||||
|
||||
<div align="center"> <img src="../pics//15b45dc6-27aa-4519-9194-f4acfa2b077f.jpg" width=""/> </div><br>
|
||||
<div align="center"> <img src="pics/15b45dc6-27aa-4519-9194-f4acfa2b077f.jpg" width=""/> </div><br>
|
||||
|
||||
# 九、线程不安全示例
|
||||
|
||||
@ -1079,19 +1079,19 @@ Java 内存模型试图屏蔽各种硬件和操作系统的内存访问差异,
|
||||
|
||||
加入高速缓存带来了一个新的问题:缓存一致性。如果多个缓存共享同一块主内存区域,那么多个缓存的数据可能会不一致,需要一些协议来解决这个问题。
|
||||
|
||||
<div align="center"> <img src="../pics//68778c1b-15ab-4826-99c0-3b4fd38cb9e9.png" width=""/> </div><br>
|
||||
<div align="center"> <img src="pics/68778c1b-15ab-4826-99c0-3b4fd38cb9e9.png" width=""/> </div><br>
|
||||
|
||||
所有的变量都存储在主内存中,每个线程还有自己的工作内存,工作内存存储在高速缓存或者寄存器中,保存了该线程使用的变量的主内存副本拷贝。
|
||||
|
||||
线程只能直接操作工作内存中的变量,不同线程之间的变量值传递需要通过主内存来完成。
|
||||
|
||||
<div align="center"> <img src="../pics//47358f87-bc4c-496f-9a90-8d696de94cee.png" width=""/> </div><br>
|
||||
<div align="center"> <img src="pics/47358f87-bc4c-496f-9a90-8d696de94cee.png" width=""/> </div><br>
|
||||
|
||||
## 内存间交互操作
|
||||
|
||||
Java 内存模型定义了 8 个操作来完成主内存和工作内存的交互操作。
|
||||
|
||||
<div align="center"> <img src="../pics//536c6dfd-305a-4b95-b12c-28ca5e8aa043.png" width=""/> </div><br>
|
||||
<div align="center"> <img src="pics/536c6dfd-305a-4b95-b12c-28ca5e8aa043.png" width=""/> </div><br>
|
||||
|
||||
- read:把一个变量的值从主内存传输到工作内存中
|
||||
- load:在 read 之后执行,把 read 得到的值放入工作内存的变量副本中
|
||||
@ -1114,11 +1114,11 @@ Java 内存模型保证了 read、load、use、assign、store、write、lock 和
|
||||
|
||||
下图演示了两个线程同时对 cnt 进行操作,load、assign、store 这一系列操作整体上看不具备原子性,那么在 T1 修改 cnt 并且还没有将修改后的值写入主内存,T2 依然可以读入旧值。可以看出,这两个线程虽然执行了两次自增运算,但是主内存中 cnt 的值最后为 1 而不是 2。因此对 int 类型读写操作满足原子性只是说明 load、assign、store 这些单个操作具备原子性。
|
||||
|
||||
<div align="center"> <img src="../pics//ef8eab00-1d5e-4d99-a7c2-d6d68ea7fe92.png" width=""/> </div><br>
|
||||
<div align="center"> <img src="pics/ef8eab00-1d5e-4d99-a7c2-d6d68ea7fe92.png" width=""/> </div><br>
|
||||
|
||||
AtomicInteger 能保证多个线程修改的原子性。
|
||||
|
||||
<div align="center"> <img src="../pics//952afa9a-458b-44ce-bba9-463e60162945.png" width=""/> </div><br>
|
||||
<div align="center"> <img src="pics/952afa9a-458b-44ce-bba9-463e60162945.png" width=""/> </div><br>
|
||||
|
||||
使用 AtomicInteger 重写之前线程不安全的代码之后得到以下线程安全实现:
|
||||
|
||||
@ -1226,7 +1226,7 @@ volatile 关键字通过添加内存屏障的方式来禁止指令重排,即
|
||||
|
||||
在一个线程内,在程序前面的操作先行发生于后面的操作。
|
||||
|
||||
<div align="center"> <img src="../pics//single-thread-rule.png" width=""/> </div><br>
|
||||
<div align="center"> <img src="pics/single-thread-rule.png" width=""/> </div><br>
|
||||
|
||||
### 2. 管程锁定规则
|
||||
|
||||
@ -1234,7 +1234,7 @@ volatile 关键字通过添加内存屏障的方式来禁止指令重排,即
|
||||
|
||||
一个 unlock 操作先行发生于后面对同一个锁的 lock 操作。
|
||||
|
||||
<div align="center"> <img src="../pics//monitor-lock-rule.png" width=""/> </div><br>
|
||||
<div align="center"> <img src="pics/monitor-lock-rule.png" width=""/> </div><br>
|
||||
|
||||
### 3. volatile 变量规则
|
||||
|
||||
@ -1242,7 +1242,7 @@ volatile 关键字通过添加内存屏障的方式来禁止指令重排,即
|
||||
|
||||
对一个 volatile 变量的写操作先行发生于后面对这个变量的读操作。
|
||||
|
||||
<div align="center"> <img src="../pics//volatile-variable-rule.png" width=""/> </div><br>
|
||||
<div align="center"> <img src="pics/volatile-variable-rule.png" width=""/> </div><br>
|
||||
|
||||
### 4. 线程启动规则
|
||||
|
||||
@ -1250,7 +1250,7 @@ volatile 关键字通过添加内存屏障的方式来禁止指令重排,即
|
||||
|
||||
Thread 对象的 start() 方法调用先行发生于此线程的每一个动作。
|
||||
|
||||
<div align="center"> <img src="../pics//thread-start-rule.png" width=""/> </div><br>
|
||||
<div align="center"> <img src="pics/thread-start-rule.png" width=""/> </div><br>
|
||||
|
||||
### 5. 线程加入规则
|
||||
|
||||
@ -1258,7 +1258,7 @@ Thread 对象的 start() 方法调用先行发生于此线程的每一个动作
|
||||
|
||||
Thread 对象的结束先行发生于 join() 方法返回。
|
||||
|
||||
<div align="center"> <img src="../pics//thread-join-rule.png" width=""/> </div><br>
|
||||
<div align="center"> <img src="pics/thread-join-rule.png" width=""/> </div><br>
|
||||
|
||||
### 6. 线程中断规则
|
||||
|
||||
@ -1476,7 +1476,7 @@ public class ThreadLocalExample1 {
|
||||
|
||||
它所对应的底层结构图为:
|
||||
|
||||
<div align="center"> <img src="../pics//3646544a-cb57-451d-9e03-d3c4f5e4434a.png" width=""/> </div><br>
|
||||
<div align="center"> <img src="pics/3646544a-cb57-451d-9e03-d3c4f5e4434a.png" width=""/> </div><br>
|
||||
|
||||
每个 Thread 都有一个 ThreadLocal.ThreadLocalMap 对象。
|
||||
|
||||
@ -1579,17 +1579,17 @@ JDK 1.6 引入了偏向锁和轻量级锁,从而让锁拥有了四个状态:
|
||||
|
||||
以下是 HotSpot 虚拟机对象头的内存布局,这些数据被称为 Mark Word。其中 tag bits 对应了五个状态,这些状态在右侧的 state 表格中给出。除了 marked for gc 状态,其它四个状态已经在前面介绍过了。
|
||||
|
||||
<div align="center"> <img src="../pics//bb6a49be-00f2-4f27-a0ce-4ed764bc605c.png" width="500"/> </div><br>
|
||||
<div align="center"> <img src="pics/bb6a49be-00f2-4f27-a0ce-4ed764bc605c.png" width="500"/> </div><br>
|
||||
|
||||
下图左侧是一个线程的虚拟机栈,其中有一部分称为 Lock Record 的区域,这是在轻量级锁运行过程创建的,用于存放锁对象的 Mark Word。而右侧就是一个锁对象,包含了 Mark Word 和其它信息。
|
||||
|
||||
<div align="center"> <img src="../pics//051e436c-0e46-4c59-8f67-52d89d656182.png" width="500"/> </div><br>
|
||||
<div align="center"> <img src="pics/051e436c-0e46-4c59-8f67-52d89d656182.png" width="500"/> </div><br>
|
||||
|
||||
轻量级锁是相对于传统的重量级锁而言,它使用 CAS 操作来避免重量级锁使用互斥量的开销。对于绝大部分的锁,在整个同步周期内都是不存在竞争的,因此也就不需要都使用互斥量进行同步,可以先采用 CAS 操作进行同步,如果 CAS 失败了再改用互斥量进行同步。
|
||||
|
||||
当尝试获取一个锁对象时,如果锁对象标记为 0 01,说明锁对象的锁未锁定(unlocked)状态。此时虚拟机在当前线程的虚拟机栈中创建 Lock Record,然后使用 CAS 操作将对象的 Mark Word 更新为 Lock Record 指针。如果 CAS 操作成功了,那么线程就获取了该对象上的锁,并且对象的 Mark Word 的锁标记变为 00,表示该对象处于轻量级锁状态。
|
||||
|
||||
<div align="center"> <img src="../pics//baaa681f-7c52-4198-a5ae-303b9386cf47.png" width="400"/> </div><br>
|
||||
<div align="center"> <img src="pics/baaa681f-7c52-4198-a5ae-303b9386cf47.png" width="400"/> </div><br>
|
||||
|
||||
如果 CAS 操作失败了,虚拟机首先会检查对象的 Mark Word 是否指向当前线程的虚拟机栈,如果是的话说明当前线程已经拥有了这个锁对象,那就可以直接进入同步块继续执行,否则说明这个锁对象已经被其他线程线程抢占了。如果有两条以上的线程争用同一个锁,那轻量级锁就不再有效,要膨胀为重量级锁。
|
||||
|
||||
@ -1601,7 +1601,7 @@ JDK 1.6 引入了偏向锁和轻量级锁,从而让锁拥有了四个状态:
|
||||
|
||||
当有另外一个线程去尝试获取这个锁对象时,偏向状态就宣告结束,此时撤销偏向(Revoke Bias)后恢复到未锁定状态或者轻量级锁状态。
|
||||
|
||||
<div align="center"> <img src="../pics//390c913b-5f31-444f-bbdb-2b88b688e7ce.jpg" width="600"/> </div><br>
|
||||
<div align="center"> <img src="pics/390c913b-5f31-444f-bbdb-2b88b688e7ce.jpg" width="600"/> </div><br>
|
||||
|
||||
# 十三、多线程开发良好的实践
|
||||
|
@ -30,7 +30,7 @@
|
||||
|
||||
# 一、运行时数据区域
|
||||
|
||||
<div align="center"> <img src="../pics//c9ad2bf4-5580-4018-bce4-1b9a71804d9c.png" width="450"/> </div><br>
|
||||
<div align="center"> <img src="pics/85370d54-40d1-4912-bcbe-37a2481c861d.png" width="450"/> </div><br>
|
||||
|
||||
## 程序计数器
|
||||
|
||||
@ -40,7 +40,7 @@
|
||||
|
||||
每个 Java 方法在执行的同时会创建一个栈帧用于存储局部变量表、操作数栈、常量池引用等信息。从方法调用直至执行完成的过程,就对应着一个栈帧在 Java 虚拟机栈中入栈和出栈的过程。
|
||||
|
||||
<div align="center"> <img src="../pics//926c7438-c5e1-4b94-840a-dcb24ff1dafe.png" width="500"/> </div><br>
|
||||
<div align="center"> <img src="pics/28ab96b4-82ea-4d99-99fb-b320f60d0a58.png" width="500"/> </div><br>
|
||||
|
||||
可以通过 -Xss 这个虚拟机参数来指定每个线程的 Java 虚拟机栈内存大小:
|
||||
|
||||
@ -59,7 +59,7 @@ java -Xss512M HackTheJava
|
||||
|
||||
本地方法一般是用其它语言(C、C++ 或汇编语言等)编写的,并且被编译为基于本机硬件和操作系统的程序,对待这些方法需要特别处理。
|
||||
|
||||
<div align="center"> <img src="../pics//JNI-Java-Native-Interface.jpg" width="350"/> </div><br>
|
||||
<div align="center"> <img src="pics/JNI-Java-Native-Interface.jpg" width="350"/> </div><br>
|
||||
|
||||
## 堆
|
||||
|
||||
@ -143,7 +143,7 @@ Java 虚拟机使用该算法来判断对象是否可被回收,在 Java 中 GC
|
||||
- 方法区中类静态属性引用的对象
|
||||
- 方法区中的常量引用的对象
|
||||
|
||||
<div align="center"> <img src="../pics//0635cbe8.png" width=""/> </div><br>
|
||||
<div align="center"> <img src="pics/0635cbe8.png" width=""/> </div><br>
|
||||
|
||||
### 3. 方法区的回收
|
||||
|
||||
@ -225,9 +225,9 @@ obj = null;
|
||||
|
||||
### 1. 标记 - 清除
|
||||
|
||||
<div align="center"> <img src="../pics//a4248c4b-6c1d-4fb8-a557-86da92d3a294.jpg" width=""/> </div><br>
|
||||
<div align="center"> <img src="pics/a4248c4b-6c1d-4fb8-a557-86da92d3a294.jpg" width=""/> </div><br>
|
||||
|
||||
将存活的对象进行标记,然后清理掉未被标记的对象。
|
||||
标记要回收的对象,然后清除。
|
||||
|
||||
不足:
|
||||
|
||||
@ -236,13 +236,13 @@ obj = null;
|
||||
|
||||
### 2. 标记 - 整理
|
||||
|
||||
<div align="center"> <img src="../pics//902b83ab-8054-4bd2-898f-9a4a0fe52830.jpg" width=""/> </div><br>
|
||||
<div align="center"> <img src="pics/902b83ab-8054-4bd2-898f-9a4a0fe52830.jpg" width=""/> </div><br>
|
||||
|
||||
让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。
|
||||
|
||||
### 3. 复制
|
||||
|
||||
<div align="center"> <img src="../pics//e6b733ad-606d-4028-b3e8-83c3a73a3797.jpg" width=""/> </div><br>
|
||||
<div align="center"> <img src="pics/e6b733ad-606d-4028-b3e8-83c3a73a3797.jpg" width=""/> </div><br>
|
||||
|
||||
将内存划分为大小相等的两块,每次只使用其中一块,当这一块内存用完了就将还存活的对象复制到另一块上面,然后再把使用过的内存空间进行一次清理。
|
||||
|
||||
@ -263,7 +263,7 @@ HotSpot 虚拟机的 Eden 和 Survivor 的大小比例默认为 8:1,保证了
|
||||
|
||||
## 垃圾收集器
|
||||
|
||||
<div align="center"> <img src="../pics//c625baa0-dde6-449e-93df-c3a67f2f430f.jpg" width=""/> </div><br>
|
||||
<div align="center"> <img src="pics/c625baa0-dde6-449e-93df-c3a67f2f430f.jpg" width=""/> </div><br>
|
||||
|
||||
以上是 HotSpot 虚拟机中的 7 个垃圾收集器,连线表示垃圾收集器可以配合使用。
|
||||
|
||||
@ -272,7 +272,7 @@ HotSpot 虚拟机的 Eden 和 Survivor 的大小比例默认为 8:1,保证了
|
||||
|
||||
### 1. Serial 收集器
|
||||
|
||||
<div align="center"> <img src="../pics//22fda4ae-4dd5-489d-ab10-9ebfdad22ae0.jpg" width=""/> </div><br>
|
||||
<div align="center"> <img src="pics/22fda4ae-4dd5-489d-ab10-9ebfdad22ae0.jpg" width=""/> </div><br>
|
||||
|
||||
Serial 翻译为串行,也就是说它以串行的方式执行。
|
||||
|
||||
@ -284,7 +284,7 @@ Serial 翻译为串行,也就是说它以串行的方式执行。
|
||||
|
||||
### 2. ParNew 收集器
|
||||
|
||||
<div align="center"> <img src="../pics//81538cd5-1bcf-4e31-86e5-e198df1e013b.jpg" width=""/> </div><br>
|
||||
<div align="center"> <img src="pics/81538cd5-1bcf-4e31-86e5-e198df1e013b.jpg" width=""/> </div><br>
|
||||
|
||||
它是 Serial 收集器的多线程版本。
|
||||
|
||||
@ -306,7 +306,7 @@ Serial 翻译为串行,也就是说它以串行的方式执行。
|
||||
|
||||
### 4. Serial Old 收集器
|
||||
|
||||
<div align="center"> <img src="../pics//08f32fd3-f736-4a67-81ca-295b2a7972f2.jpg" width=""/> </div><br>
|
||||
<div align="center"> <img src="pics/08f32fd3-f736-4a67-81ca-295b2a7972f2.jpg" width=""/> </div><br>
|
||||
|
||||
是 Serial 收集器的老年代版本,也是给 Client 模式下的虚拟机使用。如果用在 Server 模式下,它有两大用途:
|
||||
|
||||
@ -315,7 +315,7 @@ Serial 翻译为串行,也就是说它以串行的方式执行。
|
||||
|
||||
### 5. Parallel Old 收集器
|
||||
|
||||
<div align="center"> <img src="../pics//278fe431-af88-4a95-a895-9c3b80117de3.jpg" width=""/> </div><br>
|
||||
<div align="center"> <img src="pics/278fe431-af88-4a95-a895-9c3b80117de3.jpg" width=""/> </div><br>
|
||||
|
||||
是 Parallel Scavenge 收集器的老年代版本。
|
||||
|
||||
@ -323,7 +323,7 @@ Serial 翻译为串行,也就是说它以串行的方式执行。
|
||||
|
||||
### 6. CMS 收集器
|
||||
|
||||
<div align="center"> <img src="../pics//62e77997-6957-4b68-8d12-bfd609bb2c68.jpg" width=""/> </div><br>
|
||||
<div align="center"> <img src="pics/62e77997-6957-4b68-8d12-bfd609bb2c68.jpg" width=""/> </div><br>
|
||||
|
||||
CMS(Concurrent Mark Sweep),Mark Sweep 指的是标记 - 清除算法。
|
||||
|
||||
@ -348,17 +348,17 @@ G1(Garbage-First),它是一款面向服务端应用的垃圾收集器,
|
||||
|
||||
堆被分为新生代和老年代,其它收集器进行收集的范围都是整个新生代或者老年代,而 G1 可以直接对新生代和老年代一起回收。
|
||||
|
||||
<div align="center"> <img src="../pics//4cf711a8-7ab2-4152-b85c-d5c226733807.png" width="600"/> </div><br>
|
||||
<div align="center"> <img src="pics/4cf711a8-7ab2-4152-b85c-d5c226733807.png" width="600"/> </div><br>
|
||||
|
||||
G1 把堆划分成多个大小相等的独立区域(Region),新生代和老年代不再物理隔离。
|
||||
|
||||
<div align="center"> <img src="../pics//9bbddeeb-e939-41f0-8e8e-2b1a0aa7e0a7.png" width="600"/> </div><br>
|
||||
<div align="center"> <img src="pics/9bbddeeb-e939-41f0-8e8e-2b1a0aa7e0a7.png" width="600"/> </div><br>
|
||||
|
||||
通过引入 Region 的概念,从而将原来的一整块内存空间划分成多个的小空间,使得每个小空间可以单独进行垃圾回收。这种划分方法带来了很大的灵活性,使得可预测的停顿时间模型成为可能。通过记录每个 Region 垃圾回收时间以及回收所获得的空间(这两个值是通过过去回收的经验获得),并维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的 Region。
|
||||
|
||||
每个 Region 都有一个 Remembered Set,用来记录该 Region 对象的引用对象所在的 Region。通过使用 Remembered Set,在做可达性分析的时候就可以避免全堆扫描。
|
||||
|
||||
<div align="center"> <img src="../pics//f99ee771-c56f-47fb-9148-c0036695b5fe.jpg" width=""/> </div><br>
|
||||
<div align="center"> <img src="pics/f99ee771-c56f-47fb-9148-c0036695b5fe.jpg" width=""/> </div><br>
|
||||
|
||||
如果不计算维护 Remembered Set 的操作,G1 收集器的运作大致可划分为以下几个步骤:
|
||||
|
||||
@ -446,7 +446,7 @@ G1 把堆划分成多个大小相等的独立区域(Region),新生代和
|
||||
|
||||
## 类的生命周期
|
||||
|
||||
<div align="center"> <img src="../pics//32b8374a-e822-4720-af0b-c0f485095ea2.jpg" width=""/> </div><br>
|
||||
<div align="center"> <img src="pics/32b8374a-e822-4720-af0b-c0f485095ea2.jpg" width=""/> </div><br>
|
||||
|
||||
包括以下 7 个阶段:
|
||||
|
||||
@ -622,7 +622,7 @@ System.out.println(ConstClass.HELLOWORLD);
|
||||
|
||||
下图展示的类加载器之间的层次关系,称为类加载器的双亲委派模型(Parents Delegation Model)。该模型要求除了顶层的启动类加载器外,其余的类加载器都应有自己的父类加载器。这里类加载器之间的父子关系一般通过组合(Composition)关系来实现,而不是通过继承(Inheritance)的关系实现。
|
||||
|
||||
<div align="center"> <img src="../pics//class_loader_hierarchy.png" width="600"/> </div><br>
|
||||
<div align="center"> <img src="pics/class_loader_hierarchy.png" width="600"/> </div><br>
|
||||
|
||||
### 1. 工作过程
|
||||
|
@ -463,7 +463,7 @@ public String frequencySort(String s) {
|
||||
|
||||
它其实是三向切分快速排序的一种变种,在三向切分快速排序中,每次切分都将数组分成三个区间:小于切分元素、等于切分元素、大于切分元素,而该算法是将数组分成三个区间:等于红色、等于白色、等于蓝色。
|
||||
|
||||
<div align="center"> <img src="../pics//3b49dd67-2c40-4b81-8ad2-7bbb1fe2fcbd.png"/> </div><br>
|
||||
<div align="center"> <img src="pics/3b49dd67-2c40-4b81-8ad2-7bbb1fe2fcbd.png"/> </div><br>
|
||||
|
||||
**按颜色进行排序**
|
||||
|
||||
@ -1178,7 +1178,7 @@ public List<Integer> diffWaysToCompute(String input) {
|
||||
|
||||
### BFS
|
||||
|
||||
<div align="center"> <img src="../pics//4ff355cf-9a7f-4468-af43-e5b02038facc.jpg"/> </div><br>
|
||||
<div align="center"> <img src="pics/4ff355cf-9a7f-4468-af43-e5b02038facc.jpg"/> </div><br>
|
||||
|
||||
广度优先搜索一层一层地进行遍历,每层遍历都以上一层遍历的结果作为起点,遍历一个距离能访问到的所有节点。需要注意的是,遍历过的节点不能再次被遍历。
|
||||
|
||||
@ -1407,7 +1407,7 @@ private int getShortestPath(List<Integer>[] graphic, int start, int end) {
|
||||
|
||||
### DFS
|
||||
|
||||
<div align="center"> <img src="../pics//f7f7e3e5-7dd4-4173-9999-576b9e2ac0a2.png"/> </div><br>
|
||||
<div align="center"> <img src="pics/f7f7e3e5-7dd4-4173-9999-576b9e2ac0a2.png"/> </div><br>
|
||||
|
||||
广度优先搜索一层一层遍历,每一层得到的所有新节点,要用队列存储起来以备下一层遍历的时候再遍历。
|
||||
|
||||
@ -1718,7 +1718,7 @@ Backtracking(回溯)属于 DFS。
|
||||
|
||||
[17. Letter Combinations of a Phone Number (Medium)](https://leetcode.com/problems/letter-combinations-of-a-phone-number/description/)
|
||||
|
||||
<div align="center"> <img src="../pics//a3f34241-bb80-4879-8ec9-dff2d81b514e.jpg"/> </div><br>
|
||||
<div align="center"> <img src="pics/a3f34241-bb80-4879-8ec9-dff2d81b514e.jpg"/> </div><br>
|
||||
|
||||
```html
|
||||
Input:Digit string "23"
|
||||
@ -2295,7 +2295,7 @@ private boolean isPalindrome(String s, int begin, int end) {
|
||||
|
||||
[37. Sudoku Solver (Hard)](https://leetcode.com/problems/sudoku-solver/description/)
|
||||
|
||||
<div align="center"> <img src="../pics//1ca52246-c443-48ae-b1f8-1cafc09ec75c.png"/> </div><br>
|
||||
<div align="center"> <img src="pics/1ca52246-c443-48ae-b1f8-1cafc09ec75c.png"/> </div><br>
|
||||
|
||||
```java
|
||||
private boolean[][] rowsUsed = new boolean[9][10];
|
||||
@ -2357,7 +2357,7 @@ private int cubeNum(int i, int j) {
|
||||
|
||||
[51. N-Queens (Hard)](https://leetcode.com/problems/n-queens/description/)
|
||||
|
||||
<div align="center"> <img src="../pics//1f080e53-4758-406c-bb5f-dbedf89b63ce.jpg"/> </div><br>
|
||||
<div align="center"> <img src="pics/1f080e53-4758-406c-bb5f-dbedf89b63ce.jpg"/> </div><br>
|
||||
|
||||
在 n\*n 的矩阵中摆放 n 个皇后,并且每个皇后不能在同一行,同一列,同一对角线上,求所有的 n 皇后的解。
|
||||
|
||||
@ -2365,11 +2365,11 @@ private int cubeNum(int i, int j) {
|
||||
|
||||
45 度对角线标记数组的长度为 2 \* n - 1,通过下图可以明确 (r, c) 的位置所在的数组下标为 r + c。
|
||||
|
||||
<div align="center"> <img src="../pics//85583359-1b45-45f2-9811-4f7bb9a64db7.jpg"/> </div><br>
|
||||
<div align="center"> <img src="pics/85583359-1b45-45f2-9811-4f7bb9a64db7.jpg"/> </div><br>
|
||||
|
||||
135 度对角线标记数组的长度也是 2 \* n - 1,(r, c) 的位置所在的数组下标为 n - 1 - (r - c)。
|
||||
|
||||
<div align="center"> <img src="../pics//9e80f75a-b12b-4344-80c8-1f9ccc2d5246.jpg"/> </div><br>
|
||||
<div align="center"> <img src="pics/9e80f75a-b12b-4344-80c8-1f9ccc2d5246.jpg"/> </div><br>
|
||||
|
||||
```java
|
||||
private List<List<String>> solutions;
|
||||
@ -2551,8 +2551,10 @@ public int minPathSum(int[][] grid) {
|
||||
int[] dp = new int[n];
|
||||
for (int i = 0; i < m; i++) {
|
||||
for (int j = 0; j < n; j++) {
|
||||
if (i == 0) {
|
||||
dp[j] = dp[j - 1];
|
||||
if (j == 0) {
|
||||
dp[j] = dp[j]; // 只能从上侧走到该位置
|
||||
} else if (i == 0) {
|
||||
dp[j] = dp[j - 1]; // 只能从左侧走到该位置
|
||||
} else {
|
||||
dp[j] = Math.min(dp[j - 1], dp[j]);
|
||||
}
|
||||
@ -2569,7 +2571,7 @@ public int minPathSum(int[][] grid) {
|
||||
|
||||
题目描述:统计从矩阵左上角到右下角的路径总数,每次只能向右或者向下移动。
|
||||
|
||||
<div align="center"> <img src="../pics//7c98e1b6-c446-4cde-8513-5c11b9f52aea.jpg"/> </div><br>
|
||||
<div align="center"> <img src="pics/7c98e1b6-c446-4cde-8513-5c11b9f52aea.jpg"/> </div><br>
|
||||
|
||||
```java
|
||||
public int uniquePaths(int m, int n) {
|
||||
@ -3300,7 +3302,7 @@ public int combinationSum4(int[] nums, int target) {
|
||||
|
||||
题目描述:交易之后需要有一天的冷却时间。
|
||||
|
||||
<div align="center"> <img src="../pics//a3da4342-078b-43e2-b748-7e71bec50dc4.png"/> </div><br>
|
||||
<div align="center"> <img src="pics/a3da4342-078b-43e2-b748-7e71bec50dc4.png"/> </div><br>
|
||||
|
||||
```java
|
||||
public int maxProfit(int[] prices) {
|
||||
@ -3341,7 +3343,7 @@ The total profit is ((8 - 1) - 2) + ((9 - 4) - 2) = 8.
|
||||
|
||||
题目描述:每交易一次,都要支付一定的费用。
|
||||
|
||||
<div align="center"> <img src="../pics//61942711-45a0-4e11-bbc9-434e31436f33.png"/> </div><br>
|
||||
<div align="center"> <img src="pics/61942711-45a0-4e11-bbc9-434e31436f33.png"/> </div><br>
|
||||
|
||||
```java
|
||||
public int maxProfit(int[] prices, int fee) {
|
||||
@ -5297,7 +5299,7 @@ private void inOrder(TreeNode node, List<Integer> nums) {
|
||||
|
||||
### Trie
|
||||
|
||||
<div align="center"> <img src="../pics//5c638d59-d4ae-4ba4-ad44-80bdc30f38dd.jpg"/> </div><br>
|
||||
<div align="center"> <img src="pics/5c638d59-d4ae-4ba4-ad44-80bdc30f38dd.jpg"/> </div><br>
|
||||
|
||||
Trie,又称前缀树或字典树,用于判断字符串是否存在或者是否具有某种字符串前缀。
|
||||
|
@ -157,7 +157,7 @@ Linux 发行版是 Linux 内核及各种应用软件的集成版本。
|
||||
- 编辑模式(Insert mode):按下 "i" 等按键之后进入,可以对文本进行编辑;
|
||||
- 指令列模式(Bottom-line mode):按下 ":" 按键之后进入,用于保存退出等操作。
|
||||
|
||||
<div align="center"> <img src="../pics//5942debd-fc00-477a-b390-7c5692cc8070.jpg" width="400"/> </div><br>
|
||||
<div align="center"> <img src="pics/5942debd-fc00-477a-b390-7c5692cc8070.jpg" width="400"/> </div><br>
|
||||
|
||||
在指令列模式下,有以下命令用于离开或者保存文件。
|
||||
|
||||
@ -191,25 +191,25 @@ GNU 计划,译为革奴计划,它的目标是创建一套完全自由的操
|
||||
|
||||
IDE(ATA)全称 Advanced Technology Attachment,接口速度最大为 133MB/s,因为并口线的抗干扰性太差,且排线占用空间较大,不利电脑内部散热,已逐渐被 SATA 所取代。
|
||||
|
||||
<div align="center"> <img src="../pics//924914c0-660c-4e4a-bbc0-1df1146e7516.jpg" width="400"/> </div><br>
|
||||
<div align="center"> <img src="pics/924914c0-660c-4e4a-bbc0-1df1146e7516.jpg" width="400"/> </div><br>
|
||||
|
||||
### 2. SATA
|
||||
|
||||
SATA 全称 Serial ATA,也就是使用串口的 ATA 接口,抗干扰性强,且对数据线的长度要求比 ATA 低很多,支持热插拔等功能。SATA-II 的接口速度为 300MiB/s,而新的 SATA-III 标准可达到 600MiB/s 的传输速度。SATA 的数据线也比 ATA 的细得多,有利于机箱内的空气流通,整理线材也比较方便。
|
||||
|
||||
<div align="center"> <img src="../pics//f9f2a16b-4843-44d1-9759-c745772e9bcf.jpg" width=""/> </div><br>
|
||||
<div align="center"> <img src="pics/f9f2a16b-4843-44d1-9759-c745772e9bcf.jpg" width=""/> </div><br>
|
||||
|
||||
### 3. SCSI
|
||||
|
||||
SCSI 全称是 Small Computer System Interface(小型机系统接口),经历多代的发展,从早期的 SCSI-II 到目前的 Ultra320 SCSI 以及 Fiber-Channel(光纤通道),接口型式也多种多样。SCSI 硬盘广为工作站级个人电脑以及服务器所使用,因此会使用较为先进的技术,如碟片转速 15000rpm 的高转速,且传输时 CPU 占用率较低,但是单价也比相同容量的 ATA 及 SATA 硬盘更加昂贵。
|
||||
|
||||
<div align="center"> <img src="../pics//f0574025-c514-49f5-a591-6d6a71f271f7.jpg" width=""/> </div><br>
|
||||
<div align="center"> <img src="pics/f0574025-c514-49f5-a591-6d6a71f271f7.jpg" width=""/> </div><br>
|
||||
|
||||
### 4. SAS
|
||||
|
||||
SAS(Serial Attached SCSI)是新一代的 SCSI 技术,和 SATA 硬盘相同,都是采取序列式技术以获得更高的传输速度,可达到 6Gb/s。此外也透过缩小连接线改善系统内部空间等。
|
||||
|
||||
<div align="center"> <img src="../pics//6729baa0-57d7-4817-b3aa-518cbccf824c.jpg" width=""/> </div><br>
|
||||
<div align="center"> <img src="pics/6729baa0-57d7-4817-b3aa-518cbccf824c.jpg" width=""/> </div><br>
|
||||
|
||||
## 磁盘的文件名
|
||||
|
||||
@ -244,7 +244,7 @@ GPT 没有扩展分区概念,都是主分区,每个 LAB 可以分 4 个分
|
||||
|
||||
MBR 不支持 2.2 TB 以上的硬盘,GPT 则最多支持到 2<sup>33</sup> TB = 8 ZB。
|
||||
|
||||
<div align="center"> <img src="../pics//GUID_Partition_Table_Scheme.svg.png" width="400"/> </div><br>
|
||||
<div align="center"> <img src="pics/GUID_Partition_Table_Scheme.svg.png" width="400"/> </div><br>
|
||||
|
||||
## 开机检测程序
|
||||
|
||||
@ -252,7 +252,7 @@ MBR 不支持 2.2 TB 以上的硬盘,GPT 则最多支持到 2<sup>33</sup> TB
|
||||
|
||||
BIOS(Basic Input/Output System,基本输入输出系统),它是一个固件(嵌入在硬件中的软件),BIOS 程序存放在断电后内容不会丢失的只读内存中。
|
||||
|
||||
<div align="center"> <img src="../pics//50831a6f-2777-46ea-a571-29f23c85cc21.jpg"/> </div><br>
|
||||
<div align="center"> <img src="pics/50831a6f-2777-46ea-a571-29f23c85cc21.jpg"/> </div><br>
|
||||
|
||||
BIOS 是开机的时候计算机执行的第一个程序,这个程序知道可以开机的磁盘,并读取磁盘第一个扇区的主要开机记录(MBR),由主要开机记录(MBR)执行其中的开机管理程序,这个开机管理程序会加载操作系统的核心文件。
|
||||
|
||||
@ -260,7 +260,7 @@ BIOS 是开机的时候计算机执行的第一个程序,这个程序知道可
|
||||
|
||||
下图中,第一扇区的主要开机记录(MBR)中的开机管理程序提供了两个选单:M1、M2,M1 指向了 Windows 操作系统,而 M2 指向其它分区的启动扇区,里面包含了另外一个开机管理程序,提供了一个指向 Linux 的选单。
|
||||
|
||||
<div align="center"> <img src="../pics//f900f266-a323-42b2-bc43-218fdb8811a8.jpg" width="600"/> </div><br>
|
||||
<div align="center"> <img src="pics/f900f266-a323-42b2-bc43-218fdb8811a8.jpg" width="600"/> </div><br>
|
||||
|
||||
安装多重引导,最好先安装 Windows 再安装 Linux。因为安装 Windows 时会覆盖掉主要开机记录(MBR),而 Linux 可以选择将开机管理程序安装在主要开机记录(MBR)或者其它分区的启动扇区,并且可以设置开机管理程序的选单。
|
||||
|
||||
@ -286,17 +286,17 @@ BIOS 不可以读取 GPT 分区表,而 UEFI 可以。
|
||||
- superblock:记录文件系统的整体信息,包括 inode 和 block 的总量、使用量、剩余量,以及文件系统的格式与相关信息等;
|
||||
- block bitmap:记录 block 是否被使用的位域。
|
||||
|
||||
<div align="center"> <img src="../pics//BSD_disk.png" width="800"/> </div><br>
|
||||
<div align="center"> <img src="pics/BSD_disk.png" width="800"/> </div><br>
|
||||
|
||||
## 文件读取
|
||||
|
||||
对于 Ext2 文件系统,当要读取一个文件的内容时,先在 inode 中去查找文件内容所在的所有 block,然后把所有 block 的内容读出来。
|
||||
|
||||
<div align="center"> <img src="../pics//83185315-793a-453a-a927-5e8d92b5c0ef.jpg"/> </div><br>
|
||||
<div align="center"> <img src="pics/83185315-793a-453a-a927-5e8d92b5c0ef.jpg"/> </div><br>
|
||||
|
||||
而对于 FAT 文件系统,它没有 inode,每个 block 中存储着下一个 block 的编号。
|
||||
|
||||
<div align="center"> <img src="../pics//075e1977-7846-4928-96c8-bb5b0268693c.jpg"/> </div><br>
|
||||
<div align="center"> <img src="pics/075e1977-7846-4928-96c8-bb5b0268693c.jpg"/> </div><br>
|
||||
|
||||
## 磁盘碎片
|
||||
|
||||
@ -333,7 +333,7 @@ inode 具有以下特点:
|
||||
|
||||
inode 中记录了文件内容所在的 block 编号,但是每个 block 非常小,一个大文件随便都需要几十万的 block。而一个 inode 大小有限,无法直接引用这么多 block 编号。因此引入了间接、双间接、三间接引用。间接引用是指,让 inode 记录的引用 block 块记录引用信息。
|
||||
|
||||
<div align="center"> <img src="../pics//inode_with_signatures.jpg" width="600"/> </div><br>
|
||||
<div align="center"> <img src="pics/inode_with_signatures.jpg" width="600"/> </div><br>
|
||||
|
||||
## 目录
|
||||
|
||||
@ -359,7 +359,7 @@ ext3/ext4 文件系统引入了日志功能,可以利用日志来修复文件
|
||||
- /usr (unix software resource):所有系统默认软件都会安装到这个目录;
|
||||
- /var (variable):存放系统或程序运行过程中的数据文件。
|
||||
|
||||
<div align="center"> <img src="../pics//linux-filesystem.png" width=""/> </div><br>
|
||||
<div align="center"> <img src="pics/linux-filesystem.png" width=""/> </div><br>
|
||||
|
||||
# 五、文件
|
||||
|
||||
@ -534,7 +534,7 @@ cp [-adfilprsu] source destination
|
||||
-f :如果目标文件存在时,先删除目标文件
|
||||
```
|
||||
|
||||
<div align="center"> <img src="../pics//b8081c84-62c4-4019-b3ee-4bd0e443d647.jpg"/> </div><br>
|
||||
<div align="center"> <img src="pics/b8081c84-62c4-4019-b3ee-4bd0e443d647.jpg"/> </div><br>
|
||||
|
||||
### 1. 实体链接
|
||||
|
||||
@ -655,7 +655,7 @@ example: find . -name "shadow*"
|
||||
|
||||
+4、4 和 -4 的指示的时间范围如下:
|
||||
|
||||
<div align="center"> <img src="../pics//658fc5e7-79c0-4247-9445-d69bf194c539.png" width=""/> </div><br>
|
||||
<div align="center"> <img src="pics/658fc5e7-79c0-4247-9445-d69bf194c539.png" width=""/> </div><br>
|
||||
|
||||
**② 与文件拥有者和所属群组有关的选项**
|
||||
|
||||
@ -1168,7 +1168,7 @@ dmtsai lines: 5 columns: 9
|
||||
| Z | zombie (terminated but not reaped by its parent) |
|
||||
| T | stopped (either by a job control signal or because it is being traced) |
|
||||
<br>
|
||||
<div align="center"> <img src="../pics//76a49594323247f21c9b3a69945445ee.png" width=""/> </div><br>
|
||||
<div align="center"> <img src="pics/76a49594323247f21c9b3a69945445ee.png" width=""/> </div><br>
|
||||
|
||||
## SIGCHLD
|
||||
|
||||
@ -1181,7 +1181,7 @@ dmtsai lines: 5 columns: 9
|
||||
|
||||
在子进程退出时,它的进程描述符不会立即释放,这是为了让父进程得到子进程信息,父进程通过 wait() 和 waitpid() 来获得一个已经退出的子进程的信息。
|
||||
|
||||
<div align="center"> <img src="../pics//flow.png" width=""/> </div><br>
|
||||
<div align="center"> <img src="pics/flow.png" width=""/> </div><br>
|
||||
|
||||
## wait()
|
||||
|
@ -42,7 +42,7 @@ B+ Tree 是基于 B Tree 和叶子节点顺序访问指针进行实现,它具
|
||||
|
||||
在 B+ Tree 中,一个节点中的 key 从左到右非递减排列,如果某个指针的左右相邻 key 分别是 key<sub>i</sub> 和 key<sub>i+1</sub>,且不为 null,则该指针指向节点的所有 key 大于等于 key<sub>i</sub> 且小于等于 key<sub>i+1</sub>。
|
||||
|
||||
<div align="center"> <img src="../pics//061c88c1-572f-424f-b580-9cbce903a3fe.png"/> </div><br>
|
||||
<div align="center"> <img src="pics/061c88c1-572f-424f-b580-9cbce903a3fe.png"/> </div><br>
|
||||
|
||||
### 2. 操作
|
||||
|
||||
@ -84,11 +84,11 @@ B+ Tree 是基于 B Tree 和叶子节点顺序访问指针进行实现,它具
|
||||
|
||||
InnoDB 的 B+Tree 索引分为主索引和辅助索引。主索引的叶子节点 data 域记录着完整的数据记录,这种索引方式被称为聚簇索引。因为无法把数据行存放在两个不同的地方,所以一个表只能有一个聚簇索引。
|
||||
|
||||
<div align="center"> <img src="../pics//c28c6fbc-2bc1-47d9-9b2e-cf3d4034f877.jpg"/> </div><br>
|
||||
<div align="center"> <img src="pics/c28c6fbc-2bc1-47d9-9b2e-cf3d4034f877.jpg"/> </div><br>
|
||||
|
||||
辅助索引的叶子节点的 data 域记录着主键的值,因此在使用辅助索引进行查找时,需要先查找到主键值,然后再到主索引中进行查找。
|
||||
|
||||
<div align="center"> <img src="../pics//7ab8ca28-2a41-4adf-9502-cc0a21e63b51.jpg"/> </div><br>
|
||||
<div align="center"> <img src="pics/7ab8ca28-2a41-4adf-9502-cc0a21e63b51.jpg"/> </div><br>
|
||||
|
||||
### 2. 哈希索引
|
||||
|
||||
@ -350,7 +350,7 @@ MySQL 提供了 FROM_UNIXTIME() 函数把 UNIX 时间戳转换为日期,并提
|
||||
|
||||
当一个表的数据不断增多时,Sharding 是必然的选择,它可以将数据分布到集群的不同节点上,从而缓存单个数据库的压力。
|
||||
|
||||
<div align="center"> <img src="../pics//63c2909f-0c5f-496f-9fe5-ee9176b31aba.jpg"/> </div><br>
|
||||
<div align="center"> <img src="pics/63c2909f-0c5f-496f-9fe5-ee9176b31aba.jpg"/> </div><br>
|
||||
|
||||
## 垂直切分
|
||||
|
||||
@ -358,7 +358,7 @@ MySQL 提供了 FROM_UNIXTIME() 函数把 UNIX 时间戳转换为日期,并提
|
||||
|
||||
在数据库的层面使用垂直切分将按数据库中表的密集程度部署到不同的库中,例如将原来的电商数据库垂直切分成商品数据库、用户数据库等。
|
||||
|
||||
<div align="center"> <img src="../pics//e130e5b8-b19a-4f1e-b860-223040525cf6.jpg"/> </div><br>
|
||||
<div align="center"> <img src="pics/e130e5b8-b19a-4f1e-b860-223040525cf6.jpg"/> </div><br>
|
||||
|
||||
## Sharding 策略
|
||||
|
||||
@ -392,7 +392,7 @@ MySQL 提供了 FROM_UNIXTIME() 函数把 UNIX 时间戳转换为日期,并提
|
||||
- **I/O 线程** :负责从主服务器上读取二进制日志,并写入从服务器的重放日志(Replay log)中。
|
||||
- **SQL 线程** :负责读取重放日志并重放其中的 SQL 语句。
|
||||
|
||||
<div align="center"> <img src="../pics//master-slave.png"/> </div><br>
|
||||
<div align="center"> <img src="pics/master-slave.png"/> </div><br>
|
||||
|
||||
## 读写分离
|
||||
|
||||
@ -406,7 +406,7 @@ MySQL 提供了 FROM_UNIXTIME() 函数把 UNIX 时间戳转换为日期,并提
|
||||
|
||||
读写分离常用代理方式来实现,代理服务器接收应用层传来的读写请求,然后决定转发到哪个服务器。
|
||||
|
||||
<div align="center"> <img src="../pics//master-slave-proxy.png"/> </div><br>
|
||||
<div align="center"> <img src="pics/master-slave-proxy.png"/> </div><br>
|
||||
|
||||
# 参考资料
|
||||
|
@ -67,7 +67,7 @@ Redis 支持很多特性,例如将内存中的数据持久化到硬盘中,
|
||||
|
||||
## STRING
|
||||
|
||||
<div align="center"> <img src="../pics//6019b2db-bc3e-4408-b6d8-96025f4481d6.png" width="400"/> </div><br>
|
||||
<div align="center"> <img src="pics/6019b2db-bc3e-4408-b6d8-96025f4481d6.png" width="400"/> </div><br>
|
||||
|
||||
```html
|
||||
> set hello world
|
||||
@ -82,7 +82,7 @@ OK
|
||||
|
||||
## LIST
|
||||
|
||||
<div align="center"> <img src="../pics//fb327611-7e2b-4f2f-9f5b-38592d408f07.png" width="400"/> </div><br>
|
||||
<div align="center"> <img src="pics/fb327611-7e2b-4f2f-9f5b-38592d408f07.png" width="400"/> </div><br>
|
||||
|
||||
```html
|
||||
> rpush list-key item
|
||||
@ -110,7 +110,7 @@ OK
|
||||
|
||||
## SET
|
||||
|
||||
<div align="center"> <img src="../pics//cd5fbcff-3f35-43a6-8ffa-082a93ce0f0e.png" width="400"/> </div><br>
|
||||
<div align="center"> <img src="pics/cd5fbcff-3f35-43a6-8ffa-082a93ce0f0e.png" width="400"/> </div><br>
|
||||
|
||||
```html
|
||||
> sadd set-key item
|
||||
@ -144,7 +144,7 @@ OK
|
||||
|
||||
## HASH
|
||||
|
||||
<div align="center"> <img src="../pics//7bd202a7-93d4-4f3a-a878-af68ae25539a.png" width="400"/> </div><br>
|
||||
<div align="center"> <img src="pics/7bd202a7-93d4-4f3a-a878-af68ae25539a.png" width="400"/> </div><br>
|
||||
|
||||
```html
|
||||
> hset hash-key sub-key1 value1
|
||||
@ -175,7 +175,7 @@ OK
|
||||
|
||||
## ZSET
|
||||
|
||||
<div align="center"> <img src="../pics//1202b2d6-9469-4251-bd47-ca6034fb6116.png" width="400"/> </div><br>
|
||||
<div align="center"> <img src="pics/1202b2d6-9469-4251-bd47-ca6034fb6116.png" width="400"/> </div><br>
|
||||
|
||||
```html
|
||||
> zadd zset-key 728 member1
|
||||
@ -317,11 +317,11 @@ int dictRehash(dict *d, int n) {
|
||||
|
||||
跳跃表是基于多指针有序链表实现的,可以看成多个有序链表。
|
||||
|
||||
<div align="center"> <img src="../pics//beba612e-dc5b-4fc2-869d-0b23408ac90a.png"/> </div><br>
|
||||
<div align="center"> <img src="pics/beba612e-dc5b-4fc2-869d-0b23408ac90a.png"/> </div><br>
|
||||
|
||||
在查找时,从上层指针开始查找,找到对应的区间之后再到下一层去查找。下图演示了查找 22 的过程。
|
||||
|
||||
<div align="center"> <img src="../pics//0ea37ee2-c224-4c79-b895-e131c6805c40.png"/> </div><br>
|
||||
<div align="center"> <img src="pics/0ea37ee2-c224-4c79-b895-e131c6805c40.png"/> </div><br>
|
||||
|
||||
与红黑树等平衡树相比,跳跃表具有以下优点:
|
||||
|
||||
@ -472,7 +472,7 @@ Redis 服务器是一个事件驱动程序。
|
||||
|
||||
Redis 基于 Reactor 模式开发了自己的网络事件处理器,使用 I/O 多路复用程序来同时监听多个套接字,并将到达的事件传送给文件事件分派器,分派器会根据套接字产生的事件类型调用相应的事件处理器。
|
||||
|
||||
<div align="center"> <img src="../pics//9ea86eb5-000a-4281-b948-7b567bd6f1d8.png"/> </div><br>
|
||||
<div align="center"> <img src="pics/9ea86eb5-000a-4281-b948-7b567bd6f1d8.png"/> </div><br>
|
||||
|
||||
## 时间事件
|
||||
|
||||
@ -525,7 +525,7 @@ def main():
|
||||
|
||||
从事件处理的角度来看,服务器运行流程如下:
|
||||
|
||||
<div align="center"> <img src="../pics//c0a9fa91-da2e-4892-8c9f-80206a6f7047.png" width="400"/> </div><br>
|
||||
<div align="center"> <img src="pics/c0a9fa91-da2e-4892-8c9f-80206a6f7047.png" width="400"/> </div><br>
|
||||
|
||||
# 十一、复制
|
||||
|
||||
@ -545,7 +545,7 @@ def main():
|
||||
|
||||
随着负载不断上升,主服务器可能无法很快地更新所有从服务器,或者重新连接和重新同步从服务器将导致系统超载。为了解决这个问题,可以创建一个中间层来分担主服务器的复制工作。中间层的服务器是最上层服务器的从服务器,又是最下层服务器的主服务器。
|
||||
|
||||
<div align="center"> <img src="../pics//395a9e83-b1a1-4a1d-b170-d081e7bb5bab.png" width="600"/> </div><br>
|
||||
<div align="center"> <img src="pics/395a9e83-b1a1-4a1d-b170-d081e7bb5bab.png" width="600"/> </div><br>
|
||||
|
||||
# 十二、Sentinel
|
||||
|
||||
@ -580,7 +580,7 @@ Sentinel(哨兵)可以监听集群中的服务器,并在主服务器进入
|
||||
|
||||
Redis 没有关系型数据库中的表这一概念来将同种类型的数据存放在一起,而是使用命名空间的方式来实现这一功能。键名的前面部分存储命名空间,后面部分的内容存储 ID,通常使用 : 来进行分隔。例如下面的 HASH 的键名为 article:92617,其中 article 为命名空间,ID 为 92617。
|
||||
|
||||
<div align="center"> <img src="../pics//7c54de21-e2ff-402e-bc42-4037de1c1592.png" width="400"/> </div><br>
|
||||
<div align="center"> <img src="pics/7c54de21-e2ff-402e-bc42-4037de1c1592.png" width="400"/> </div><br>
|
||||
|
||||
## 点赞功能
|
||||
|
||||
@ -588,13 +588,13 @@ Redis 没有关系型数据库中的表这一概念来将同种类型的数据
|
||||
|
||||
为了节约内存,规定一篇文章发布满一周之后,就不能再对它进行投票,而文章的已投票集合也会被删除,可以为文章的已投票集合设置一个一周的过期时间就能实现这个规定。
|
||||
|
||||
<div align="center"> <img src="../pics//485fdf34-ccf8-4185-97c6-17374ee719a0.png" width="400"/> </div><br>
|
||||
<div align="center"> <img src="pics/485fdf34-ccf8-4185-97c6-17374ee719a0.png" width="400"/> </div><br>
|
||||
|
||||
## 对文章进行排序
|
||||
|
||||
为了按发布时间和点赞数进行排序,可以建立一个文章发布时间的有序集合和一个文章点赞数的有序集合。(下图中的 score 就是这里所说的点赞数;下面所示的有序集合分值并不直接是时间和点赞数,而是根据时间和点赞数间接计算出来的)
|
||||
|
||||
<div align="center"> <img src="../pics//f7d170a3-e446-4a64-ac2d-cb95028f81a8.png" width="800"/> </div><br>
|
||||
<div align="center"> <img src="pics/f7d170a3-e446-4a64-ac2d-cb95028f81a8.png" width="800"/> </div><br>
|
||||
|
||||
# 参考资料
|
||||
|
@ -46,7 +46,7 @@ Unix 有五种 I/O 模型:
|
||||
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
|
||||
```
|
||||
|
||||
<div align="center"> <img src="../pics//1492928416812_4.png"/> </div><br>
|
||||
<div align="center"> <img src="pics/1492928416812_4.png"/> </div><br>
|
||||
|
||||
## 非阻塞式 I/O
|
||||
|
||||
@ -54,7 +54,7 @@ ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *
|
||||
|
||||
由于 CPU 要处理更多的系统调用,因此这种模型的 CPU 利用率是比较低的。
|
||||
|
||||
<div align="center"> <img src="../pics//1492929000361_5.png"/> </div><br>
|
||||
<div align="center"> <img src="pics/1492929000361_5.png"/> </div><br>
|
||||
|
||||
## I/O 复用
|
||||
|
||||
@ -64,7 +64,7 @@ ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *
|
||||
|
||||
如果一个 Web 服务器没有 I/O 复用,那么每一个 Socket 连接都需要创建一个线程去处理。如果同时有几万个连接,那么就需要创建相同数量的线程。相比于多进程和多线程技术,I/O 复用不需要进程线程创建和切换的开销,系统开销更小。
|
||||
|
||||
<div align="center"> <img src="../pics//1492929444818_6.png"/> </div><br>
|
||||
<div align="center"> <img src="pics/1492929444818_6.png"/> </div><br>
|
||||
|
||||
## 信号驱动 I/O
|
||||
|
||||
@ -72,7 +72,7 @@ ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *
|
||||
|
||||
相比于非阻塞式 I/O 的轮询方式,信号驱动 I/O 的 CPU 利用率更高。
|
||||
|
||||
<div align="center"> <img src="../pics//1492929553651_7.png"/> </div><br>
|
||||
<div align="center"> <img src="pics/1492929553651_7.png"/> </div><br>
|
||||
|
||||
## 异步 I/O
|
||||
|
||||
@ -80,7 +80,7 @@ ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *
|
||||
|
||||
异步 I/O 与信号驱动 I/O 的区别在于,异步 I/O 的信号是通知应用进程 I/O 完成,而信号驱动 I/O 的信号是通知应用进程可以开始 I/O。
|
||||
|
||||
<div align="center"> <img src="../pics//1492930243286_8.png"/> </div><br>
|
||||
<div align="center"> <img src="pics/1492930243286_8.png"/> </div><br>
|
||||
|
||||
## 五大 I/O 模型比较
|
||||
|
||||
@ -91,7 +91,7 @@ ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *
|
||||
|
||||
非阻塞式 I/O 、信号驱动 I/O 和异步 I/O 在第一阶段不会阻塞。
|
||||
|
||||
<div align="center"> <img src="../pics//1492928105791_3.png"/> </div><br>
|
||||
<div align="center"> <img src="pics/1492928105791_3.png"/> </div><br>
|
||||
|
||||
# 二、I/O 复用
|
||||
|
||||
@ -178,12 +178,12 @@ else if ( ret == 0 )
|
||||
else
|
||||
{
|
||||
// If we detect the event, zero it out so we can reuse the structure
|
||||
if ( pfd[0].revents & POLLIN )
|
||||
pfd[0].revents = 0;
|
||||
if ( fds[0].revents & POLLIN )
|
||||
fds[0].revents = 0;
|
||||
// input event on sock1
|
||||
|
||||
if ( pfd[1].revents & POLLOUT )
|
||||
pfd[1].revents = 0;
|
||||
if ( fds[1].revents & POLLOUT )
|
||||
fds[1].revents = 0;
|
||||
// output event on sock2
|
||||
}
|
||||
```
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 47 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 409 KiB After Width: | Height: | Size: 409 KiB |
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 37 KiB |
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 9.0 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 7.0 KiB After Width: | Height: | Size: 7.0 KiB |
Before Width: | Height: | Size: 129 KiB After Width: | Height: | Size: 129 KiB |
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 43 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 7.0 KiB After Width: | Height: | Size: 7.0 KiB |
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |