ARTS 挑战打卡第十一周(200720-200726)
Algorthm
https://leetcode.com/problems/maximum-binary-tree/
思路:题目说的最大二叉树是指根节点是数组中最大的值,左子树是最大值左边的值构成的最大二叉树(根节点是左半部分最大值),右子树是最大值右边的值构成的最大二叉树(根节点是右半部分最大值)。
有点像快速排序的思路,先找出最大值,然后以最大值为分隔点,继续递归地处理左右两部分的元素。
Review
给分布式系统工程师准备的分布式系统理论:
适合分布式系统工程师看的分布式系统理论,作者认为,推荐大量的理论论文是学习分布式系统理论的错误方法,除非是去读博士。因为论文通常难度大且较复杂,且需要了解论文产生的背景才能领悟到其中的精妙之处。
作者整理了分布式工程师必须要掌握的知识列表,掌握这些就足够设计出新的分布式系统了。可以仔细翻阅,里面推荐的资料都很精彩。
作者首先推荐了四个资料:
Distributed Systems for Fun and Profit - 分布式系统袖珍书
Notes on distributed systems for young bloods - 分布式系统学习笔记
https://www.somethingsimilar.com/2013/01/14/notes-on-distributed-systems-for-young-bloods/
A Note on Distributed Systems - 一篇经典的论文,讲述不能把所有的远程交互当作本地对象处理
http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.41.7628
The fallacies of distributed computing - 学习分布式系统时常见的8个错误假设
https://en.wikipedia.org/wiki/Fallacies_of_distributed_computing
随后,作者分享了几个关键的知识点:
1、失败和时间,分布式系统中,很多问题的根本原因都是:
进程挂了
不知道如何证明进程挂了
这两者之间的关联非常强,如何确定事件发生的顺序变得非常重要,大多数情况下,都假设两个节点间完全没有共享时钟。
2、容错的压力(The basic tension of fault tolerance)
一个系统能在不降级的情况下容错的系统要像没有错误发生的那样运行。这就意味着,系统的某些部分必须冗余地工作,从而在性能和资源消耗两方面带来成本。
最终一致性以及其他技术方案在以系统行为弱保证为代价,来试图避免这种系统压力。阅读 Dynamo 论文和帕特·赫尔兰(Pat Helland)的经典论文 Life Beyond Transactions 能获很大启发。
3、基本原语(Basic primitives)
在分布式系统中几乎没有一致认同的基础模块,但现在开始越来越多地在出现。比如 Leader 选举,可以参考Bully算法;分布式状态机复制,可以参考维基百科和 Lampson 的论文,后者更权威,只是有些枯燥。
4、基本结论(Fundamental Results)
某些事实是需要吸收理解的,有几点:
如果进程之间可能丢失某些消息,那么不可能在实现一致性存储的同时响应所有的请求,这就是 CAP 定理;
一致性不可能同时满足以下条件:a. 总是正确,b. 在异步系统中只要有一台机器发生故障,系统总是能终止运行——停止失败(FLP 不可能性);
一般而言,消息交互少于两轮都不可能达成共识(Consensus);
原子地广播与共识一样难解决,如果解决了原子广播问题,那就是解决了共识问题,反过来也一样。
5、真实系统(Real systems)
学习分布式系统架构最重要的是,结合一些真实系统的描述,反复思考和点评其背后的设计决策。如谷歌的 GFS、Spanner、Chubby、BigTable、Dapper 等,以及 Dryad、Cassandra 和 Ceph 等非谷歌系统。
其他资料链接:
Lamport clocks-Lamport逻辑时钟
https://amturing.acm.org/p558-lamport.pdf
Dynamo-Amozon分布式存储经典论文
https://www.allthingsdistributed.com/files/amazon-dynamo-sosp2007.pdf
Atomic broadcast-原子广播
http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.3.4709&rep=rep1&type=pdf
Tip
为什么我们调用-start-方法时会执行-run-方法,为什么我们不能直接调用-run-方法?
新建一个线程,(new Thread),线程进入了新建状态,调用start()方法,会启动一个线程并使线程进入了就绪状态,当分配到时间片后就可以开始运行了。start()会执行线程的相应准备工作,然后自动执行run()方法,这是真正的多线程工作。
直接执行run()方法,会把run方法当成一个main线程下的普通方法去执行,并不会在某个线程中执行它,所以这并不是多线程工作。
总结:调用start方法才可以启动线程并使线程进入就绪状态,而run方法只是thread对象的一个普通方法调用,还是在主线程里执行。
简述HashMap的实现原理
HashMap概述
HashMap是一个保存键值对的数据结构,是基于哈希表的Map接口的非同步实现。此实现提供所有可选的映射操作,并允许使用null值和null键。HashMap不保证映射的顺序,特别是它不保证该顺序永久不变。
HashMap的数据结构
在Java中,只有两种基本的数据结构,数组和指针(引用),所有的数据结构都可以用这两种基本结构组成,比如链表、树等等,HashMap是一个数组+链表+红黑树(JDK1.8增加了红黑树部分,后两者都是引用类型)的结合体。
HashMap的操作实现
往HashMap新增元素的操作是put,当调用put方法时,首先根据key的hashcode重新计算key的hash值,根据hash值得到这个元素在数组中的下标,如果计算出来的下标已经有其他元素,那么在这个hash位置上的元素就会以链表的结构存储,且是头部插入的方式,新加入的节点在链头;如果下标没有元素,则直接存储到数组上。
在Java8中,对HashMap的实现作了优化,当保存重复hash的链表中的节点数据超过了8个之后,链表会转换为红黑树存储来提高查询效率,查询时间复杂度由O(n)到O(logn)。
Share
分享文章:Java 8系列之重新认识HashMap
https://tech.meituan.com/2016/06/24/java-hashmap.html
比较清晰地介绍了HashMap的实现原理,结合文章去看源码,基本就掌握HashMap的实现了。
版权声明: 本文为 InfoQ 作者【老胡爱分享】的原创文章。
原文链接:【http://xie.infoq.cn/article/6eb026a2adb000c198d462ffb】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论