Skip to content

Commit c21e06f

Browse files
author
minibear2333
committed
更新若干知识体系
1 parent 9d726fc commit c21e06f

27 files changed

+940
-126
lines changed

SUMMARY.md

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,17 @@
77
* [LeetCode-hot100-medium](LeetCode/hot100/medium.md)
88
* [LeetCode-hot100-difficult](LeetCode/hot100/difficult.md)
99
* [其他高频算法](LeetCode/other.md)
10-
* [面试高频问题-操作系统](interview/操作系统.md)
11-
* [面试高频问题-linux](interview/linux.md)
12-
* [面试高频问题-go](interview/go.md)
13-
* [面试高频问题-redis](interview/redis.md)
14-
* [面试高频问题-mysql](interview/mysql.md)
15-
* [面试高频问题-网络](interview/网络.md)
16-
* [面试高频问题-docker](interview/docker.md)
17-
* [面试高频问题-k8s](interview/k8s.md)
18-
* [TODO面试高频问题-前端](interview/前端.md)
19-
* [TODO面试高频问题-mongoDB](interview/mongoDB.md)
20-
* [面试高频问题-待解答](interview/todo.md)
10+
* [数据结构](interview/数据结构.md)
11+
* [操作系统](interview/操作系统.md)
12+
* [Linux](interview/linux.md)
13+
* [Go](interview/go.md)
14+
* [Java](interview/Java.md)
15+
* [Redis](interview/redis.md)
16+
* [Mysql](interview/mysql.md)
17+
* [网络](interview/网络.md)
18+
* [Docker](interview/docker.md)
19+
* [k8s](interview/k8s.md)
20+
* [TODO-前端](interview/前端.md)
21+
* [TODO-mongoDB](interview/mongoDB.md)
22+
* [待解答](interview/todo.md)
2123
* [协作办法](leetcode-vscode.md)

interview/2021年/202103下.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,3 +156,36 @@ bfs 镜像二叉树、反转二叉树
156156
#### 如何使用random4随机4函数,来实现random7随机7函数?
157157

158158
2021-03-19
159+
160+
### 其他
161+
162+
#### 什么是分布式锁,怎么用的?
163+
164+
卑微小王:
165+
多机环境下的锁机制就是分布式锁,一般依赖redis
166+
通过一个flagkey进行原子化的操作,获取锁(未被占用的同时实现占用,已被占用返回报错)
167+
操作执行完实现针对该锁的释放
168+
169+
锁的释放需要注意两点
170+
1.程序异常,未执行释放锁,需要对锁加过期时间,或者其他补救措施
171+
2.每个进程只能释放自己的锁(如果自己的锁因超时被释放,此时获取到的锁是别人的,跳过锁释放)
172+
173+
redis分布式锁难点一般在锁的获取
174+
我们一般用一对key:value当锁
175+
获取锁 两步:1查询value是否存在 存在则返回加锁失败,2不存在则set key:value
176+
redis有个setnx方法可以将两步同步执行
177+
以防止多人同步执行查询+set操作时有人插队
178+
179+
前端时间业务流程是直接返回给用户报错
180+
让前端用户稍后重试
181+
其他场景感觉得异步执行业务
182+
该业务包含
183+
1.获取锁
184+
2.1获取成功执行业务
185+
2.2获取失败等待下次执行
186+
3.释放锁
187+
188+
2.1-2.2感觉得架死循环每段时间判断一次,但是这种用于大流量一旦一个业务处理时间过长
189+
可能内部线程会被打爆
190+
191+
补充:总共要设计两个超时,获取不到立即返回/锁超时自动释放,使用锁及时续期

interview/Java.md

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
### 基本数据类型
2+
3+
* 整型:byte(8)、short(16)、int(32)、long(64)
4+
* 浮点型:float(32)、double(64)
5+
* 布尔型:boolean(8)
6+
* 字符型:char(16)
7+
* 只能向上转型
8+
* += 或者 ++ 运算符会执行隐式类型转换
9+
10+
### 异常处理
11+
12+
![](../res/2021-03-26-16-30-18.png)
13+
14+
#### 三种类型的异常
15+
16+
* **检查性异常:**最具代表的检查性异常是用户错误或问题引起的异常,这是程序员无法预见的。例如要打开一个不存在文件时,一个异常就发生了,这些异常在编译时不能被简单地忽略。
17+
* **运行时异常:** 运行时异常是可能被程序员避免的异常。与检查性异常相反,运行时异常可以在编译时被忽略。
18+
* **错误:** 错误不是异常,而是脱离程序员控制的问题。错误在代码中通常被忽略。例如,当栈溢出时,一个错误就发生了,它们在编译也检查不到的。
19+
20+
#### 关键字
21+
22+
* try/catch:捕获异常,catch可以多重捕获(直到异常被捕获或者通过所有的 catch 块)
23+
* throws/throw:方法使用 throws 关键字来声明(一个方法没有捕获到一个检查性异常),throw 关键字抛出一个异常
24+
* finally:在 try 代码块后面执行的代码块
25+
26+
#### 自定义异常
27+
28+
* 所有异常都必须是 Throwable 的子类。
29+
* 自定义检查性异常类,需要继承 Exception 类。
30+
* 自定义运行时异常类,那么需要继承 RuntimeException 类。
31+
32+
### hashMap
33+
34+
* 底层数据结构,JDK 1.8 是**数组 + 链表 + 红黑树**,JDK 1.7 无红黑树。
35+
* 初始容量为 **16**,通过 tableSizeFor 保证容量为 2 的幂次方。寻址方式,高位异或,**(n-1)&h** 取模,优化速度。
36+
* 扩容机制,当元素数量大于容量 x 负载因子 0.75 时,容量扩大为原来的 2 倍,新建一个数组,然后转移到新数组。
37+
* 基于 Map 实现。
38+
* 线程不安全。
39+
* key的hashCode()做hash,然后再计算index(高位运算和取模运算)
40+
* 指针数组,value为链表,长度大于 8 时,转化为红黑树(1.8),优化查询效率。
41+
+ 当 HashMap 中有大量的元素都存放到同一个桶中时,这个时候 HashMap 就相当于一个单链表,遍历时间复杂度就是 O(n)
42+
+ 转换为红黑树:时间复杂度为 O(logn)
43+
* 当限制n为2的幂次方时,**(n-1)&h**和h%n结果一致,但效率高了很多倍
44+
45+
![](../res/2021-03-26-16-30-40.png)
46+
47+
![](../res/2021-03-26-16-30-59.png)
48+
49+
### ConcurrentHashMap的实现原理
50+
51+
* 采用了数组+链表+红黑树的实现方式来设计
52+
* ConcurrentHashMap的主干是个Segment数组
53+
+ Segment继承了ReentrantLock,重入锁
54+
+ Segment类似于HashMap,一个Segment维护着一个HashEntry数组
55+
* 分段锁
56+
* 内部大量采用CAS操作
57+
+ 比较交换
58+
+ 乐观锁
59+
+ 包含三个操作数 —— 内存位置(V)、预期原值(A)和新值(B)
60+
* 链表:保存key,value及key的hash值的数据结构,value和next都用volatile修饰
61+
62+
### final关键字
63+
64+
* 修饰类不能被继承
65+
* 修饰方法:不能被重写
66+
* 修饰变量:基本数据类型不能被修改;引用类型初始化后不能指向另一个对象
67+
68+
### String实现
69+
70+
* 属性value:char[]
71+
* String不可变:
72+
+ 实现字符串池(String pool)
73+
+ 多线程安全
74+
+ 避免安全问题
75+
+ 加快字符串处理速度(hashMap的key方便计算hashcode)
76+
* Equals:
77+
+ this == anObject
78+
+ anObject instanceof String
79+
+ 比较value属性
80+
+ 重写hashCode方法
81+
82+
### clone
83+
84+
* clone() 是 Object 的 protected 方法,不是 public,一个类不显式去重写 clone(),其它类就不能直接去调用该类实例的 clone() 方法。
85+
* Cloneable 接口规定:一个类没有实现 Cloneable 接口又调用了 clone() 方法,就会抛出 CloneNotSupportedException
86+
* 浅拷贝:拷贝对象和原始对象的引用类型引用同一个对象
87+
* 深拷贝:拷贝对象和原始对象的引用类型引用不同对象
88+
* 使用 clone() 方法来拷贝一个对象即复杂又有风险,它会抛出异常,并且还需要类型转换。可以使用拷贝构造函数或者拷贝工厂来拷贝一个对象
89+
90+
### volatile
91+
92+
* 在多线程环境下,保证变量的可见性。使用了 volatile 修饰变量后,**在变量修改后会立即同步到主存中,每次用这个变量前会从主存刷新。**
93+
* 禁止 JVM 指令重排序。
94+
95+
![](../res/2021-03-26-16-31-24.png)
96+
97+
### synchronized
98+
99+
* 三种应用方式:
100+
+ 修饰实例方法,作用于当前实例加锁,进入同步代码前要获得当前实例的锁
101+
+ 修饰静态方法,作用于当前类对象加锁,进入同步代码前要获得当前类对象的锁
102+
+ 修饰代码块,指定加锁对象,对给定对象加锁,进入同步代码库前要获得给定对象的锁。
103+
104+
### 偏向锁,自旋锁,轻量级锁(乐观锁)重量级锁(悲观锁)
105+
106+
* 通过 synchronized 加锁,第一个线程获取的锁为偏向锁,这时有其他线程参与锁竞争,升级为轻量级锁,其他线程通过循环的方式尝试获得锁,称自旋锁。若果自旋的次数达到一定的阈值,则升级为重量级锁。
107+
* 需要注意的是,在第二个线程获取锁时,会先判断第一个线程是否仍然存活,如果不存活,不会升级为轻量级锁。
108+
109+
![](../res/2021-03-26-16-31-49.png)
110+
111+
### AQS(一个用来构建锁和同步器的框架)
112+
113+
* 结构
114+
+ 用 volatile 修饰的整数类型的 state 状态(持有锁的次数),用于表示同步状态,提供 getState 和 setState 来操作同步状态;
115+
+ 提供了一个 FIFO 等待队列,实现线程间的竞争和等待,这是 AQS 的核心;
116+
+ AQS 内部提供了各种基于 CAS 原子操作方法,如 compareAndSetState 方法,并且提供了锁操作的acquire和release方法。
117+
* 独占锁模式
118+
+ 用 state 值表示锁并且 0 表示无锁状态,0 -> 1 表示从无锁到有锁,
119+
+ 仅允许一条线程持有锁,其余的线程会被包装成一个 Node 节点放到队列中进行挂起
120+
+ 队列中的头节点表示当前正在执行的线程,当头节点释放后会唤醒后继节点
121+
* 共享锁模式
122+
+ 当有一个线程获取到锁之后,那么它就会依次唤醒等待队列中可以跟它共享的节点
123+
124+
### ReentrantLock
125+
126+
* 基于 AQS (AbstractQueuedSynchronizer)实现,主要有 state (资源) + FIFO (线程等待队列) 组成。
127+
* 公平锁与非公平锁:区别在于在获取锁时,公平锁会判断当前队列是否有正在等待的线程,如果有则进行排队。
128+
* 使用 lock() 和 unLock() 方法来加锁解锁。
129+
* 非公平锁吞吐量高
130+
131+
在获取锁的阶段来分析,当某一线程要获取锁时,非公平锁可以直接尝试获取锁,而不是判断当前队列中是否有线程在等待。一定情况下可以避免线程频繁的上下文切换,这样,活跃的线程有可能获得锁,而在队列中的锁还要进行唤醒才能继续尝试获取锁,而且线程的执行顺序一般来说不影响程序的运行。
132+
133+
### 线程池
134+
135+
* 分类
136+
+ FixThreadPool 固定数量的线程池,适用于对线程管理,高负载的系统
137+
+ SingleThreadPool 只有一个线程的线程池,适用于保证任务顺序执行
138+
+ CacheThreadPool 创建一个不限制线程数量的线程池,适用于执行短期异步任务的小程序,低负载系统
139+
+ ScheduledThreadPool 定时任务使用的线程池,适用于定时任务
140+
141+
* 重要参数
142+
+ int corePoolSize, 核心线程数
143+
+ int maximumPoolSize, 最大线程数
144+
+ long keepAliveTime, TimeUnit unit, 超过 corePoolSize 的线程的存活时长,超过这个时间,多余的线程会被回收。
145+
+ `BlockingQueue<Runnable> workQueue`, 任务的排队队列
146+
+ ThreadFactory threadFactory, 新线程的产生方式
147+
+ RejectedExecutionHandler handler) 拒绝策略
148+
149+
* 线程池线程工作过程
150+
151+
corePoolSize -> 任务队列 -> maximumPoolSize -> 拒绝策略
152+
153+
> 核心线程在线程池中一直存活,当有任务需要执行时,直接使用核心线程执行任务。当任务数量大于核心线程数时,加入等待队列。当任务队列数量达到队列最大长度时,继续创建线程,最多达到最大线程数。当设置回收时间时,核心线程以外的空闲线程会被回收。如果达到了最大线程数还不能够满足任务执行需求,则根据拒绝策略做拒绝处理。
154+
155+
### 反射
156+
157+
**反射就是在运行时才知道要操作的类是什么,并且可以在运行时获取类的完整构造,并调用对应的方法**
158+
159+
#### 常用方法
160+
161+
* 获取反射中的Class对象`Class clz`
162+
+ 使用 Class.forName 静态方法`Class.forName("java.lang.String")`
163+
+ 使用 .class 方法`String.class`
164+
+ 使用类对象的 getClass() 方法`new String("Hello").getClass()`
165+
* 通过反射创建类对象(通过 Constructor 对象创建类对象可以选择特定构造方法,通过 Class 对象则只能使用默认的无参数构造方法)
166+
+ 通过 Class 对象的 newInstance() 方法`(Apple)clz.newInstance()`
167+
+ 通过 Constructor 对象的 newInstance() 方法`Constructor constructor = clz.getConstructor(); Apple apple = (Apple)constructor.newInstance();`
168+
* 通过反射获取类属性、方法、构造器
169+
+ Class 对象的 getFields() 方法可以获取 Class 类的属性(无法获取私有属性)
170+
+ Class 对象的 getDeclaredFields() 方法则可以获取包括私有属性在内的所有属性
171+
172+
### 注解
173+
174+
#### 注解的作用
175+
176+
* 由编译器使用的注解:不会被编译进入`.class`文件,在编译后就被编译器扔掉(@Override@SuppressWarnings
177+
* 由工具处理.class文件使用的注解:会被编译进入`.class`文件,但加载结束后并不会存在于内存中
178+
* 在程序运行期能够读取的注解:在加载后一直存在于JVM中
179+
180+
#### 配置参数
181+
182+
可以有默认值;大部分注解会有一个名为 `value` 的配置参数,可以省略value参数
183+
184+
* 所有基本类型;
185+
* String;
186+
* 枚举类型;
187+
* 基本类型、String、Class以及枚举的数组
188+
189+
#### 定义方式
190+
191+
* 使用`@interface`语法来定义注解
192+
*`default`设定一个默认值(强烈推荐)
193+
194+
#### 元注解
195+
196+
* 修饰其他注解的注解
197+
* Java标准库定义
198+
* 常用
199+
+ @Target:定义`Annotation`能够被应用于源码的哪些位置(数组)
200+
- 类或接口:`ElementType.TYPE`
201+
- 字段:`ElementType.FIELD`
202+
- 方法:`ElementType.METHOD`
203+
- 构造方法:`ElementType.CONSTRUCTOR`
204+
- 方法参数:`ElementType.PARAMETER`
205+
+ @Retention:定义`Annotation`的生命周期(默认值CLASS)
206+
- `RetentionPolicy.SOURCE`:在编译期就被丢掉(由编译器使用)
207+
- `RetentionPolicy.CLASS`:仅保存在class文件中,它们不会被加载进JVM(主要由底层工具库使用)
208+
- RetentionPolicy.RUNTIME`:会被加载进JVM,并且在运行期可以被程序读取
209+
+ @Repeatabl:定义`Annotation`是否可重复
210+
+ @Inherited:定义子类是否可继承父类定义的`Annotation`
211+
212+
#### 使用方式
213+
214+
注解定义后也是一种 `class` ,所有的注解都继承自 `java.lang.annotation.Annotation` 。读取注解,需要使用反射API
215+
216+
* `Class.isAnnotationPresent(Class)`
217+
* `Field.isAnnotationPresent(Class)`
218+
* `Method.isAnnotationPresent(Class)`
219+
* `Constructor.isAnnotationPresent(Class)`

interview/docker.md

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
### 介绍一下docker
1+
### 介绍docker
22

33
docker是go开发的,基于Apache2.0协议开源,可以把应用和他的依赖打包到一个轻量级、方便移植的系统中,主要解决的问题是快速发布、自动化构建、统一测试成功的环境和线上环境
44

@@ -20,22 +20,19 @@ docker分为镜像、容器、仓库,打包好的叫镜像,存储镜像的
2020

2121
按层构建,基于一个基础层添加新层,前一层是后一层的基础,构建完就变成只读的了,每一层都意味着不同的操作指令,比如初始化环境、程序入口等
2222

23-
### docker有哪几种网络模式?
23+
### docker网络模式
2424

25-
bridge
25+
Docker使用Linux的Namespaces技术来进行资源隔离
2626

27-
默认模式,在主机上创建一个名为 `docker0` 的虚拟网桥,此主机上启动的 `Docker` 容器会连接到这个虚拟网桥上。虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器就通过交换机连在了一个二层网络中。
27+
* container模式:和一个已经存在的容器共享`Network namespace`,不创建自己的网卡,也不配置自己的ip,共享同一个`ip`和共享的端口范围,但文件系统和进程列表还是隔离的,同样是用到`veth`设置拉到`docker0`上,`docker0`是默认网关,转发到宿主机上
2828

29-
`docker0` 子网中分配一个 IP 给容器使用,并设置 docker0 的 IP 地址为容器的**默认网关**。在主机上创建一对虚拟网卡 `veth pair` 设备,Docker 将 veth pair 设备的一端放在新创建的容器中,并命名为 `eth0` (容器的网卡),另一端放在主机中,以 `vethxxx` 这样类似的名字命名,并将这个网络设备加入到 docker0 网桥中。可以通过 `brctl show` 命令查看。
29+
* host模式:和主机共享网络,但文件系统和进程列表还是隔离的,容器将不会获得一个独立的`Network Namespace`,而是和宿主机共用一个`Network Namespace`。容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口
3030

31-
container
31+
* none模式:Docker容器拥有自己的Network Namespace,但不为Docker容器进行任何网络配置,没有网卡、IP、路由等信息
3232

33-
和容器共享network namespace,不和宿主机共享,容器拥有同一个ip和共享的端口范围,但文件系统和进程列表还是隔离的,同样是用到veth设置拉到docker0上,docker0是默认网关,转发到宿主机上
33+
* bridge模式:默认模式,在主机上创建一个名为 `docker0` 的虚拟网桥,此主机上启动的 `Docker` 容器会连接到这个虚拟网桥上。虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器就通过交换机连在了一个二层网络中。
34+
-`docker0` 子网中分配一个 IP 给容器使用,并设置 docker0 的 IP 地址为容器的**默认网关**。在主机上创建一对虚拟网卡 `veth pair` 设备,Docker 将 veth pair 设备的一端放在新创建的容器中,并命名为 `eth0` (容器的网卡),另一端放在主机中,以 `vethxxx` 这样类似的名字命名,并将这个网络设备加入到 docker0 网桥中。可以通过 `brctl show` 命令查看。
35+
- 选择一个和宿主机不同的IP地址和子网分配给docker0,连接到docker0的容器就从这个子网中选择一个未占用的IP使用
3436

35-
host
37+
![](../res/2021-03-26-16-42-00.png)
3638

37-
和主机共享网络,但文件系统和进程列表还是隔离的
38-
39-
none
40-
41-
就是容器里没有网卡

0 commit comments

Comments
 (0)