Skip to content

Commit e3fede5

Browse files
committed
智力题
1 parent 71888c1 commit e3fede5

16 files changed

+85
-82
lines changed

MD/Java基础-IO.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,24 @@ Block-IO:InputStream和OutputStream,Reader和Writer。属于同步阻塞模
33

44
同步阻塞:一个请求占用一个进程处理,先等待数据准备好,然后从内核向进程复制数据,最后处理完数据后返回
55

6-
![](https://github.com/xbox1994/2018-Java-Interview/raw/master/images/BIO.png)
6+
![](https://github.com/xbox1994/Java-Interview/raw/master/images/BIO.png)
77

88
## NIO
99
NonBlock-IO:Channel、Buffer、Selector。属于IO多路复用的同步非阻塞模型
1010

1111
同步非阻塞:进程先将一个套接字在内核中设置成非阻塞再等待数据准备好,在这个过程中反复轮询内核数据是否准备好,准备好之后最后处理数据返回
1212

13-
![](https://github.com/xbox1994/2018-Java-Interview/raw/master/images/NIO-1.png)
13+
![](https://github.com/xbox1994/Java-Interview/raw/master/images/NIO-1.png)
1414

1515
IO多路复用:同步非阻塞的优化版本,区别在于IO多路复用阻塞在select,epoll这样的系统调用之上,而没有阻塞在真正的IO系统调用上。换句话说,轮询机制被优化成通知机制,多个连接公用一个阻塞对象,进程只需要在一个阻塞对象上等待,无需再轮询所有连接
1616

17-
![](https://github.com/xbox1994/2018-Java-Interview/raw/master/images/NIO-3.png)
17+
![](https://github.com/xbox1994/Java-Interview/raw/master/images/NIO-3.png)
1818

1919
在Java的NIO中,是基于Channel和Buffer进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。Selector用于监听多个通道的事件(比如:连接打开,数据到达)
2020

2121
因此,单个线程可以监听多个数据通道,Selector的底层实现是epoll/poll/select的IO多路复用模型,select方法会一直阻塞,直到channel中有事件就绪:
2222

23-
![](https://github.com/xbox1994/2018-Java-Interview/raw/master/images/NIO-4.png)
23+
![](https://github.com/xbox1994/Java-Interview/raw/master/images/NIO-4.png)
2424

2525
与BIO区别如下:
2626

@@ -31,7 +31,7 @@ IO多路复用:同步非阻塞的优化版本,区别在于IO多路复用阻
3131
## AIO
3232
Asynchronous IO:属于事件和回调机制的异步非阻塞模型
3333

34-
![](https://github.com/xbox1994/2018-Java-Interview/raw/master/images/AIO.png)
34+
![](https://github.com/xbox1994/Java-Interview/raw/master/images/AIO.png)
3535

3636
AIO得到结果的方式:
3737

MD/Java基础-JVM原理.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
### Java内存区域的分配
33
JVM虚拟机内存模型实现规范:
44

5-
![](https://github.com/xbox1994/2018-Java-Interview/raw/master/images/JVM规范.png)
5+
![](https://github.com/xbox1994/Java-Interview/raw/master/images/JVM规范.png)
66

77

88
按线程是否共享分为以下区域:
@@ -20,7 +20,7 @@ JVM虚拟机内存模型实现规范:
2020

2121
以HotSpot虚拟机实现为例,Java8中内存区域如下:
2222

23-
![](https://github.com/xbox1994/2018-Java-Interview/raw/master/images/JVM1.8.png)
23+
![](https://github.com/xbox1994/Java-Interview/raw/master/images/JVM1.8.png)
2424

2525
与规范中的区别:
2626

@@ -60,7 +60,7 @@ JVM虚拟机内存模型实现规范:
6060
3. 为了实现代码热替换,OSGi是为了实现自己的类加载逻辑,用平级查找的逻辑替换掉了向下传递的逻辑。但其实可以不破坏双亲委派逻辑而是自定义类加载器来达到代码热替换。比如[这篇文章](https://www.cnblogs.com/pfxiong/p/4070462.html)
6161

6262
### 内存分配(堆上的内存分配)
63-
![](https://github.com/xbox1994/2018-Java-Interview/raw/master/images/堆的内存分配.png)
63+
![](https://github.com/xbox1994/Java-Interview/raw/master/images/堆的内存分配.png)
6464
#### 新生代
6565
##### 进入条件
6666
优先选择在新生代的Eden区被分配。
@@ -134,7 +134,7 @@ STW总会发生,不管是新生代还是老年代,比如CMS在初始标记
134134

135135
实现:volatile、synchronized、final、concurrent包等。其实这些就是Java内存模型封装了底层的实现后提供给程序员使用的一些关键字
136136

137-
![](https://github.com/xbox1994/2018-Java-Interview/raw/master/images/j12.jpg)
137+
![](https://github.com/xbox1994/Java-Interview/raw/master/images/j12.jpg)
138138

139139
主内存:所有变量都保存在主内存中
140140
工作内存:每个线程的独立内存,保存了该线程使用到的变量的主内存副本拷贝,线程对变量的操作必须在工作内存中进行

MD/Java基础-多线程.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
### 线程的生命周期
33
新建 -- 就绪 -- 运行 -- 阻塞 -- 就绪 -- 运行 -- 死亡
44

5-
![](https://github.com/xbox1994/2018-Java-Interview/raw/master/images/j13.png)
5+
![](https://github.com/xbox1994/Java-Interview/raw/master/images/j13.png)
66

77
### 问:你怎么理解多线程的
88

@@ -122,7 +122,7 @@ new Thread弊端:
122122
#### CountDownLatch
123123
计数器闭锁是一个能阻塞主线程,让其他线程满足特定条件下主线程再继续执行的线程同步工具。
124124

125-
![](https://github.com/xbox1994/2018-Java-Interview/raw/master/images/countdownlatch.png)
125+
![](https://github.com/xbox1994/Java-Interview/raw/master/images/countdownlatch.png)
126126
图中,A为主线程,A首先设置计数器的数到AQS的state中,当调用await方法之后,A线程阻塞,随后每次其他线程调用countDown的时候,将state减1,直到计数器为0的时候,A线程继续执行。
127127

128128
使用场景:
@@ -164,7 +164,7 @@ public class CountDownLatchTest {
164164
#### CyclicBarrier
165165
可以让一组线程相互等待,当每个线程都准备好之后,所有线程才继续执行的工具类
166166

167-
![](https://github.com/xbox1994/2018-Java-Interview/raw/master/images/cyclicbarrier.png)
167+
![](https://github.com/xbox1994/Java-Interview/raw/master/images/cyclicbarrier.png)
168168

169169
与CountDownLatch类似,都是通过计数器实现的,当某个线程调用await之后,计数器减1,当计数器大于0时将等待的线程包装成AQS的Node放入等待队列中,当计数器为0时将等待队列中的Node拿出来执行。
170170

MD/Java基础-集合.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,12 @@
2020
HashTable 在每次同步执行时都要锁住整个结构。ConcurrentHashMap 锁的方式是稍微细粒度的。 ConcurrentHashMap 将 hash 表分为 16 个桶(默认值)
2121
最大并发个数就是Segment的个数,默认值是16,可以通过构造函数改变一经创建不可更改,这个值就是并发的粒度,每一个segment下面管理一个table数组,加锁的时候其实锁住的是整个segment
2222
#### Java7
23-
![](https://github.com/xbox1994/2018-Java-Interview/raw/master/images/j3.jpg)
23+
![](https://github.com/xbox1994/Java-Interview/raw/master/images/j3.jpg)
2424

2525
ConcurrentHashMap 类中包含两个静态内部类 HashEntry 和 Segment。HashEntry 用来封装映射表的键 / 值对;Segment 用来充当锁的角色,每个 Segment 对象守护整个散列映射表的若干个桶。每个桶是由若干个 HashEntry 对象链接起来的链表。一个 ConcurrentHashMap 实例中包含由若干个 Segment 对象组成的数组。
2626

2727
#### Java8
28-
![](https://github.com/xbox1994/2018-Java-Interview/raw/master/images/j4.jpg)
28+
![](https://github.com/xbox1994/Java-Interview/raw/master/images/j4.jpg)
2929

3030
1. 为进一步提高并发性,放弃了分段锁,锁的级别控制在了更细粒度的table元素级别,也就是说只需要锁住这个链表的head节点,并不会影响其他的table元素的读写,好处在于并发的粒度更细,影响更小,从而并发效率更好
3131
2. 使用CAS + synchronized 来保证实现put操作:如果Key对应的数组元素为null,则通过CAS操作将其设置为当前值。如果Key对应的数组元素(也即链表表头或者树的根元素)不为null,则对该元素使用synchronized关键字申请锁,然后进行操作。如果该put操作使得当前链表长度超过一定阈值,则将链表(寻址时间复杂度为O(N))转换为红黑树(寻址时间复杂度为O(log(N)),插入操作完成之后如果所有元素的数量大于当前容量(默认16)*负载因子(默认0.75)就进行扩容。

MD/分布式-一致性hash.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,30 +14,30 @@
1414

1515
一致 Hash 算法是将所有的哈希值构成了一个环,其范围在 `0 ~ 2^32-1`。如下图:
1616

17-
![](https://github.com/xbox1994/2018-Java-Interview/raw/master/images/一致性hash1.jpg)
17+
![](https://github.com/xbox1994/Java-Interview/raw/master/images/一致性hash1.jpg)
1818

1919
之后将各个节点散列到这个环上,可以用节点的 IP、hostname 这样的唯一性字段作为 Key 进行 `hash(key)`,散列之后如下:
2020

21-
![](https://github.com/xbox1994/2018-Java-Interview/raw/master/images/一致性hash2.jpg)
21+
![](https://github.com/xbox1994/Java-Interview/raw/master/images/一致性hash2.jpg)
2222

2323
之后需要将数据定位到对应的节点上,使用同样的 `hash 函数` 将 Key 也映射到这个环上。
2424

25-
![](https://github.com/xbox1994/2018-Java-Interview/raw/master/images/一致性hash3.jpg)
25+
![](https://github.com/xbox1994/Java-Interview/raw/master/images/一致性hash3.jpg)
2626

2727
这样按照顺时针方向就可以把 k1 定位到 `N1节点`,k2 定位到 `N3节点`,k3 定位到 `N2节点`
2828

2929
### 容错性
3030
这时假设 N1 宕机了:
3131

32-
![](https://github.com/xbox1994/2018-Java-Interview/raw/master/images/一致性hash4.jpg)
32+
![](https://github.com/xbox1994/Java-Interview/raw/master/images/一致性hash4.jpg)
3333

3434
依然根据顺时针方向,k2 和 k3 保持不变,只有 k1 被重新映射到了 N3。这样就很好的保证了容错性,当一个节点宕机时只会影响到少少部分的数据。
3535

3636
### 拓展性
3737

3838
当新增一个节点时:
3939

40-
![](https://github.com/xbox1994/2018-Java-Interview/raw/master/images/一致性hash5.jpg)
40+
![](https://github.com/xbox1994/Java-Interview/raw/master/images/一致性hash5.jpg)
4141

4242
在 N2 和 N3 之间新增了一个节点 N4 ,这时会发现受印象的数据只有 k3,其余数据也是保持不变,所以这样也很好的保证了拓展性。
4343

@@ -46,13 +46,13 @@
4646

4747
当节点较少时会出现数据分布不均匀的情况:
4848

49-
![](https://github.com/xbox1994/2018-Java-Interview/raw/master/images/一致性hash6.jpg)
49+
![](https://github.com/xbox1994/Java-Interview/raw/master/images/一致性hash6.jpg)
5050

5151
这样会导致大部分数据都在 N1 节点,只有少量的数据在 N2 节点。
5252

5353
为了解决这个问题,一致哈希算法引入了虚拟节点。将每一个节点都进行多次 hash,生成多个节点放置在环上称为虚拟节点:
5454

55-
![](https://github.com/xbox1994/2018-Java-Interview/raw/master/images/一致性hash7.jpg)
55+
![](https://github.com/xbox1994/Java-Interview/raw/master/images/一致性hash7.jpg)
5656

5757
计算时可以在 IP 后加上编号来生成哈希值。
5858

MD/分布式-事务.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
如果你要操作别人的服务的库,你必须是通过**调用别的服务的接口**来实现,绝对不允许交叉访问别人的数据库。
1111

12-
![](https://github.com/xbox1994/2018-Java-Interview/raw/master/images/分布式事务1.png)
12+
![](https://github.com/xbox1994/Java-Interview/raw/master/images/分布式事务1.png)
1313

1414
### TCC 方案
1515
TCC 的全称是:Try、Confirm、Cancel。
@@ -26,7 +26,7 @@ TCC 的全称是:Try、Confirm、Cancel。
2626

2727
但是说实话,一般尽量别这么搞,自己手写回滚逻辑,或者是补偿逻辑,实在太恶心了,那个业务代码很难维护。
2828

29-
![](https://github.com/xbox1994/2018-Java-Interview/raw/master/images/分布式事务2.png)
29+
![](https://github.com/xbox1994/Java-Interview/raw/master/images/分布式事务2.png)
3030

3131
### 本地消息表
3232
本地消息表其实是国外的 ebay 搞出来的这么一套思想。
@@ -42,7 +42,7 @@ TCC 的全称是:Try、Confirm、Cancel。
4242

4343
这个方案说实话最大的问题就在于**严重依赖于数据库的消息表来管理事务**啥的,会导致如果是高并发场景咋办呢?咋扩展呢?所以一般确实很少用。
4444

45-
![](https://github.com/xbox1994/2018-Java-Interview/raw/master/images/分布式事务3.png)
45+
![](https://github.com/xbox1994/Java-Interview/raw/master/images/分布式事务3.png)
4646

4747
### 可靠消息最终一致性方案
4848
这个的意思,就是干脆不要用本地的消息表了,直接基于 MQ 来实现事务。比如阿里的 RocketMQ 就支持消息事务。
@@ -56,7 +56,7 @@ TCC 的全称是:Try、Confirm、Cancel。
5656
5. 这个方案里,要是系统 B 的事务失败了咋办?重试咯,自动不断重试直到成功,如果实在是不行,要么就是针对重要的资金类业务进行回滚,比如 B 系统本地回滚后,想办法通知系统 A 也回滚;或者是发送报警由人工来手工回滚和补偿。
5757
6. 这个还是比较合适的,目前国内互联网公司大都是这么玩儿的,要不你举用 RocketMQ 支持的,要不你就自己基于类似 ActiveMQ?RabbitMQ?自己封装一套类似的逻辑出来,总之思路就是这样子的。
5858

59-
![](https://github.com/xbox1994/2018-Java-Interview/raw/master/images/分布式事务4.png)
59+
![](https://github.com/xbox1994/Java-Interview/raw/master/images/分布式事务4.png)
6060

6161
### 最大努力通知方案
6262
这个方案的大致意思就是:

MD/分布式-协调器.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
### 分布式协调
22
这个其实是 zookeeper 很经典的一个用法,简单来说,就好比,你 A 系统发送个请求到 mq,然后 B 系统消息消费之后处理了。那 A 系统如何知道 B 系统的处理结果?用 zookeeper 就可以实现分布式系统之间的协调工作。A 系统发送请求之后可以在 zookeeper 上**对某个节点的值注册个监听器**,一旦 B 系统处理完了就修改 zookeeper 那个节点的值,A 立马就可以收到通知,完美解决。
33

4-
![](https://github.com/xbox1994/2018-Java-Interview/raw/master/images/zookeeper1.png)
4+
![](https://github.com/xbox1994/Java-Interview/raw/master/images/zookeeper1.png)
55

66
### 分布式锁
77
举个栗子。对某一个数据连续发出两个修改操作,两台机器同时收到了请求,但是只能一台机器先执行完另外一个机器再执行。那么此时就可以使用 zookeeper 分布式锁,一个机器接收到了请求之后先获取 zookeeper 上的一把分布式锁,就是可以去创建一个 znode,接着执行操作;然后另外一个机器也**尝试去创建**那个 znode,结果发现自己创建不了,因为被别人创建了,那只能等着,等第一个机器执行完了自己再执行。
88

9-
![](https://github.com/xbox1994/2018-Java-Interview/raw/master/images/zookeeper2.png)
9+
![](https://github.com/xbox1994/Java-Interview/raw/master/images/zookeeper2.png)
1010

1111
### 元数据/配置信息管理
1212
zookeeper 可以用作很多系统的配置信息的管理,比如 kafka、storm 等等很多分布式系统都会选用 zookeeper 来做一些元数据、配置信息的管理,包括 dubbo 注册中心不也支持 zookeeper 么?
1313

14-
![](https://github.com/xbox1994/2018-Java-Interview/raw/master/images/zookeeper3.png)
14+
![](https://github.com/xbox1994/Java-Interview/raw/master/images/zookeeper3.png)
1515

1616
### HA高可用性
1717
这个应该是很常见的,比如 hadoop、hdfs、yarn 等很多大数据系统,都选择基于 zookeeper 来开发 HA 高可用机制,就是一个**重要进程一般会做主备**两个,主进程挂了立马通过 zookeeper 感知到切换到备用进程。
1818

19-
![](https://github.com/xbox1994/2018-Java-Interview/raw/master/images/zookeeper4.png)
19+
![](https://github.com/xbox1994/Java-Interview/raw/master/images/zookeeper4.png)
2020

2121
https://github.com/doocs/advanced-java/blob/master/docs/distributed-system/zookeeper-application-scenarios.md
2222

MD/分布式-消息队列.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ RabbitMQ 如果丢失了数据,主要是因为你消费的时候,刚消费
3434

3535
消息体通过hash分派到队列里,每个队列对应唯一一个消费者。比如下面的示例中,订单号相同的消息会被先后发送到同一个队列中:
3636

37-
![](https://github.com/xbox1994/2018-Java-Interview/raw/master/images/消息顺序性.jpg)
37+
![](https://github.com/xbox1994/Java-Interview/raw/master/images/消息顺序性.jpg)
3838

3939
在获取到路由信息以后,会根据MessageQueueSelector实现的算法来选择一个队列,同一个订单号获取到的肯定是同一个队列。
4040

@@ -56,7 +56,7 @@ Kafka 一个最基本的架构认识:由多个 broker 组成,每个 broker
5656

5757
如果某个 broker 宕机了,没事儿,那个 broker上面的 partition 在其他机器上都有副本的,如果这上面有某个 partition 的 leader,那么此时会从 follower 中重新选举一个新的 leader 出来,大家继续读写那个新的 leader 即可。这就有所谓的高可用性了。
5858

59-
![](https://github.com/xbox1994/2018-Java-Interview/raw/master/images/kafka集群.png)
59+
![](https://github.com/xbox1994/Java-Interview/raw/master/images/kafka集群.png)
6060

6161
https://github.com/doocs/advanced-java#%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97 https://dbaplus.cn/news-73-1123-1.html
6262

MD/微服务-服务注册与发现.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
客户端应用进程向注册中心发起查询,来获取服务的位置。服务发现的一个重要作用就是提供一个可用的服务列表。
55

66
## 原理
7-
![](https://github.com/xbox1994/2018-Java-Interview/raw/master/images/consul.jpg)
7+
![](https://github.com/xbox1994/Java-Interview/raw/master/images/consul.jpg)
88

99
1. 当User Service启动的时候,会向Consul发送一个POST请求,告诉Consul自己的IP和Port
1010
2. Consul 接收到User Service的注册后,每隔10s(默认)会向User Service发送一个健康检查的请求,检验User Service是否健康(Consul其实支持其他健康检查机制)

MD/微服务-服务配置中心.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
我们的每个服务的配置文件都是在自身代码库中,当服务数量达到一定数量后,管理这些分散的配置文件会成为一个痛点。这节课我么就来解决配置文件管理的痛点
22

3-
![](https://github.com/xbox1994/2018-Java-Interview/raw/master/images/config.jpg)
3+
![](https://github.com/xbox1994/Java-Interview/raw/master/images/config.jpg)
44

55
Spring Cloud Config的目标是将各个微服务的配置文件集中存储一个文件仓库中(比如系统目录,Git仓库等等),然后通过Config Server从文件仓库中去读取配置文件,而各个微服务作为Config Client通过给Config Server发送请求指令来获取特定的Profile的配置文件,从而为自身的应用提供配置信息。同时还提供配置文件自动刷新功能。
66

0 commit comments

Comments
 (0)