Merge branch 'master' of https://github.com/CyC2018/Interview-Notebook
60
README.md
@ -1,8 +1,15 @@
|
||||
[](https://gitter.im/CyC2018-Interview-Notebook/Lobby?utm_source=share-link&utm_medium=link&utm_campaign=share-link) [](https://legacy.gitbook.com/book/cyc2018/interview-notebook/details)
|
||||
|
||||
| Ⅰ | Ⅱ | Ⅲ | Ⅳ | Ⅴ | Ⅵ | Ⅶ | Ⅷ | Ⅸ | Ⅹ |
|
||||
| :--------: | :---------: | :---------: | :---------: | :---------: | :---------:| :---------: | :-------: | :-------:| :------:|
|
||||
| 算法[:pencil2:](#算法-pencil2) | 操作系统[:computer:](#操作系统-computer)|网络[:cloud:](#网络-cloud) | 面向对象[:couple:](#面向对象-couple) |数据库[:floppy_disk:](#数据库-floppy_disk)| Java [:coffee:](#java-coffee)| 分布式 [:sweat_drops:](#分布式-sweat_drops)| 工具[:hammer:](#工具-hammer)| 编码实践[:speak_no_evil:](#编码实践-speak_no_evil)| 后记[:memo:](#后记-memo) |
|
||||
| 算法[:pencil2:](#算法-pencil2) | 操作系统[:computer:](#操作系统-computer)|网络[:cloud:](#网络-cloud) | 面向对象[:couple:](#面向对象-couple) |数据库[:floppy_disk:](#数据库-floppy_disk)| Java [:coffee:](#java-coffee)| 系统设计[:bulb:](#系统设计-bulb)| 工具[:hammer:](#工具-hammer)| 编码实践[:speak_no_evil:](#编码实践-speak_no_evil)| 后记[:memo:](#后记-memo) |
|
||||
|
||||
<br>
|
||||
<div align="center">
|
||||
<img src="other/LogoMakr_0zpEzN.png" width="150px">
|
||||
<br>
|
||||
<a href="https://gitter.im/CyC2018-Interview-Notebook/Lobby?utm_source=share-link&utm_medium=link&utm_campaign=share-link"> <img src="https://img.shields.io/badge/>-gitter-4ab8a1.svg"></a> <a href="https://legacy.gitbook.com/book/cyc2018/interview-notebook/details"> <img src="https://img.shields.io/badge/_-gitbook-4ab8a1.svg"></a>
|
||||
</div>
|
||||
|
||||
<!-- [](https://gitter.im/CyC2018-Interview-Notebook/Lobby?utm_source=share-link&utm_medium=link&utm_campaign=share-link) [](https://legacy.gitbook.com/book/cyc2018/interview-notebook/details) -->
|
||||
|
||||
## 面试准备
|
||||
|
||||
@ -102,7 +109,7 @@ Leetcode 上数据库题目的解题记录。
|
||||
|
||||
包含 NIO 的原理以及实例。
|
||||
|
||||
## 分布式 :sweat_drops:
|
||||
## 系统设计 :bulb:
|
||||
|
||||
> [一致性](https://github.com/CyC2018/InnterviewNotes/blob/master/notes/一致性.md)
|
||||
|
||||
@ -138,7 +145,7 @@ Google 开源项目的代码风格规范。
|
||||
|
||||
## 后记 :memo:
|
||||
|
||||
**关于仓库**
|
||||
**About**
|
||||
|
||||
这个仓库是笔者的一个学习笔记,主要总结一些比较重要的知识点,希望对大家有所帮助。
|
||||
|
||||
@ -146,19 +153,19 @@ Google 开源项目的代码风格规范。
|
||||
|
||||
[BOOKLIST](https://github.com/CyC2018/Interview-Notebook/blob/master/BOOKLIST.md),这个书单是笔者至今看的一些比较好的技术书籍,虽然没有全都看完,但每本书多多少少都看了一部分。
|
||||
|
||||
**如何贡献**
|
||||
**How To Contribute**
|
||||
|
||||
笔记内容是笔者一个字一个字打上去的,难免会有一些笔误,如果发现笔误可直接在相应文档进行编辑修改。
|
||||
|
||||
欢迎提交对本仓库的改进建议~
|
||||
|
||||
**授权相关**
|
||||
**Authorization**
|
||||
|
||||
虽然没有加开源协议,但是允许非商业性使用。
|
||||
|
||||
转载使用请注明出处,谢谢!
|
||||
|
||||
**上传方案**
|
||||
**Uploading**
|
||||
|
||||
笔者在本地使用为知笔记软件进行书写,为了方便将本地笔记内容上传到 Github 上,实现了一整套自动化上传方案,包括文本文件的导出、提取图片、Markdown 文档转换、Git 同步。
|
||||
|
||||
@ -166,7 +173,7 @@ Google 开源项目的代码风格规范。
|
||||
|
||||
这里提供了笔者实现的 GFM 文档转换工具的链接:[GFM-Converter](https://github.com/CyC2018/GFM-Converter)。
|
||||
|
||||
**排版指南**
|
||||
**Typesetting**
|
||||
|
||||
笔记内容按照 [中文文案排版指北](http://mazhuang.org/wiki/chinese-copywriting-guidelines/) 进行排版,以保证内容的可读性。
|
||||
|
||||
@ -174,10 +181,39 @@ Google 开源项目的代码风格规范。
|
||||
|
||||
这里提供了笔者实现的中英混排文档在线排版工具的链接:[Text-Typesetting](https://github.com/CyC2018/Markdown-Typesetting)。
|
||||
|
||||
**声明**
|
||||
**Statement**
|
||||
|
||||
本仓库不参与商业行为,不向读者收取任何费用。(This repository is not engaging in business activities, and does not charge readers any fee.)
|
||||
|
||||
**鸣谢**
|
||||
**Logo**
|
||||
|
||||
Power by [logomakr](https://logomakr.com/).
|
||||
|
||||
**Acknowledgements**
|
||||
|
||||
感谢以下人员对本仓库做出的贡献,当然不仅仅只有这些贡献者,这里就不一一列举了。如果你希望被添加到这个名单中,并且提交过 Issue 或者 PR,请与笔者联系。
|
||||
|
||||
<a href="https://github.com/linw7">
|
||||
<img src="other/21679154.png" width="50px">
|
||||
</a>
|
||||
<a href="https://github.com/g10guang">
|
||||
<img src="other/18458140.jpg" width="50px">
|
||||
</a>
|
||||
<a href="https://github.com/ResolveWang">
|
||||
<img src="other/8018776.jpg" width="50px">
|
||||
</a>
|
||||
<a href="https://github.com/crossoverJie">
|
||||
<img src="other/15684156.jpg" width="50px">
|
||||
</a>
|
||||
<a href="https://github.com/jy03078584">
|
||||
<img src="other/7719370.png" width="50px">
|
||||
</a>
|
||||
<a href="https://github.com/kwongtailau">
|
||||
<img src="other/22954582.jpg" width="50px">
|
||||
</a>
|
||||
<a href="https://github.com/xiangflight">
|
||||
<img src="other/10072416.jpg" width="50px">
|
||||
</a>
|
||||
|
||||
|
||||
|
||||
[TeeKee](https://github.com/linw7) [g10guang](https://github.com/g10guang) [crossoverJie](https://github.com/crossoverJie)
|
||||
|
@ -1177,7 +1177,6 @@ Java 注解是附加在代码中的一些元信息,用于一些工具在编译
|
||||
- Java 支持自动垃圾回收,而 C++ 需要手动回收。
|
||||
- Java 不支持多重继承,只能通过实现多个接口来达到相同目的,而 C++ 支持多重继承。
|
||||
- Java 不支持操作符重载,虽然可以对两个 String 对象支持加法运算,但是这是语言内置支持的操作,不属于操作符重载,而 C++ 可以。
|
||||
- Java 内置了线程的支持,而 C++ 需要依靠第三方库。
|
||||
- Java 的 goto 是保留字,但是不可用,C++ 可以使用 goto。
|
||||
- Java 不支持条件编译,C++ 通过 #ifdef #ifndef 等预处理命令从而实现条件编译。
|
||||
|
||||
|
@ -499,7 +499,7 @@ public synchronized static void fun() {
|
||||
|
||||
## ReentrantLock
|
||||
|
||||
ReentrantLock 是 java.util.concurrent(J.U.C)包中的锁.
|
||||
ReentrantLock 是 java.util.concurrent(J.U.C)包中的锁。
|
||||
|
||||
```java
|
||||
public class LockExample {
|
||||
@ -952,7 +952,7 @@ produce..produce..consume..consume..produce..consume..produce..consume..produce.
|
||||
|
||||
```java
|
||||
public class ForkJoinExample extends RecursiveTask<Integer> {
|
||||
private final int threhold = 5;
|
||||
private final int threshold = 5;
|
||||
private int first;
|
||||
private int last;
|
||||
|
||||
@ -964,7 +964,7 @@ public class ForkJoinExample extends RecursiveTask<Integer> {
|
||||
@Override
|
||||
protected Integer compute() {
|
||||
int result = 0;
|
||||
if (last - first <= threhold) {
|
||||
if (last - first <= threshold) {
|
||||
// 任务足够小则直接计算
|
||||
for (int i = first; i <= last; i++) {
|
||||
result += i;
|
||||
@ -1134,7 +1134,7 @@ public static void main(String[] args) throws InterruptedException {
|
||||
1000
|
||||
```
|
||||
|
||||
除了使用原子类之外,也可以使用 synchronized 互斥锁来保证操作的完整性,它对应的内存间交互操作为:lock 和 unlock,在虚拟机实现上对应的字节码指令为 monitorenter 和 monitorexit。
|
||||
除了使用原子类之外,也可以使用 synchronized 互斥锁来保证操作的原子性。它对应的内存间交互操作为:lock 和 unlock,在虚拟机实现上对应的字节码指令为 monitorenter 和 monitorexit。
|
||||
|
||||
```java
|
||||
public class AtomicSynchronizedExample {
|
||||
@ -1176,9 +1176,13 @@ public static void main(String[] args) throws InterruptedException {
|
||||
|
||||
可见性指当一个线程修改了共享变量的值,其它线程能够立即得知这个修改。Java 内存模型是通过在变量修改后将新值同步回主内存,在变量读取前从主内存刷新变量值来实现可见性的。
|
||||
|
||||
volatile 可保证可见性。synchronized 也能够保证可见性,对一个变量执行 unlock 操作之前,必须把变量值同步回主内存。final 关键字也能保证可见性:被 final 关键字修饰的字段在构造器中一旦初始化完成,并且没有发生 this 逃逸(其它线程可以通过 this 引用访问到初始化了一半的对象),那么其它线程就能看见 final 字段的值。
|
||||
主要有有三种实现可见性的方式:
|
||||
|
||||
对前面的线程不安全示例中的 cnt 变量用 volatile 修饰,不能解决线程不安全问题,因为 volatile 并不能保证操作的原子性。
|
||||
- volatile
|
||||
- synchronized,对一个变量执行 unlock 操作之前,必须把变量值同步回主内存。
|
||||
- final,被 final 关键字修饰的字段在构造器中一旦初始化完成,并且没有发生 this 逃逸(其它线程通过 this 引用访问到初始化了一半的对象),那么其它线程就能看见 final 字段的值。
|
||||
|
||||
对前面的线程不安全示例中的 cnt 变量使用 volatile 修饰,不能解决线程不安全问题,因为 volatile 并不能保证操作的原子性。
|
||||
|
||||
### 3. 有序性
|
||||
|
||||
@ -1662,9 +1666,9 @@ JDK 1.6 引入了偏向锁和轻量级锁,从而让锁拥有了四个状态:
|
||||
|
||||
- 缩小同步范围,例如对于 synchronized,应该尽量使用同步块而不是同步方法。
|
||||
|
||||
- 多用同步类少用 wait() 和 notify()。首先,CountDownLatch, Semaphore, CyclicBarrier 和 Exchanger 这些同步类简化了编码操作,而用 wait() 和 notify() 很难实现对复杂控制流的控制。其次,这些类是由最好的企业编写和维护,在后续的 JDK 中它们还会不断优化和完善,使用这些更高等级的同步工具你的程序可以不费吹灰之力获得优化。
|
||||
- 多用同步类少用 wait() 和 notify()。首先,CountDownLatch, CyclicBarrier, Semaphore 和 Exchanger 这些同步类简化了编码操作,而用 wait() 和 notify() 很难实现对复杂的控制流;其次,这些同步类是由最好的企业编写和维护,在后续的 JDK 中还会不断优化和完善,使用这些更高等级的同步工具你的程序可以不费吹灰之力获得优化。
|
||||
|
||||
- 多用并发集合少用同步集合。并发集合比同步集合的可扩展性更好,例如应该使用 ConcurrentHashMap 而不是 Hashtable。
|
||||
- 多用并发集合少用同步集合,例如应该使用 ConcurrentHashMap 而不是 Hashtable。
|
||||
|
||||
- 使用本地变量和不可变类来保证线程安全。
|
||||
|
||||
|
@ -25,7 +25,7 @@
|
||||
* [六、键的过期时间](#六键的过期时间)
|
||||
* [七、数据淘汰策略](#七数据淘汰策略)
|
||||
* [八、持久化](#八持久化)
|
||||
* [快照持久化](#快照持久化)
|
||||
* [RDB 持久化](#rdb-持久化)
|
||||
* [AOF 持久化](#aof-持久化)
|
||||
* [九、发布与订阅](#九发布与订阅)
|
||||
* [十、事务](#十事务)
|
||||
@ -210,17 +210,7 @@ OK
|
||||
|
||||
## 字典
|
||||
|
||||
以下是 Redis 字典的主要数据结构,从上往下分析,一个 dict 有两个 dictht,一个 dictht 有一个 dictEntry 数组,每个 dictEntry 有 next 指针因此是一个链表结构。从上面的分析可以看出 Redis 的字典是一个基于拉链法解决冲突的哈希表结构。
|
||||
|
||||
```c
|
||||
typedef struct dict {
|
||||
dictType *type;
|
||||
void *privdata;
|
||||
dictht ht[2];
|
||||
long rehashidx; /* rehashing not in progress if rehashidx == -1 */
|
||||
unsigned long iterators; /* number of iterators currently running */
|
||||
} dict;
|
||||
```
|
||||
dictht 是一个散列表结构,使用拉链法保存哈希冲突的 dictEntry。
|
||||
|
||||
```c
|
||||
/* This is our hash table structure. Every dictionary has two of this as we
|
||||
@ -246,11 +236,21 @@ typedef struct dictEntry {
|
||||
} dictEntry;
|
||||
```
|
||||
|
||||
哈希表需要具备扩容能力,在扩容时就需要对每个键值对进行 rehash。dict 有两个 dictht,在 rehash 的时候会将一个 dictht 上的键值对重新插入另一个 dictht 上面,完成之后释放空间并交换两个 dictht 的角色。
|
||||
Redis 的字典 dict 中包含两个哈希表 dictht,这是为了方便进行 rehash 操作。在扩容时,将其中一个 dictht 上的键值对 rehash 到另一个 dictht 上面,完成之后释放空间并交换两个 dictht 的角色。
|
||||
|
||||
```c
|
||||
typedef struct dict {
|
||||
dictType *type;
|
||||
void *privdata;
|
||||
dictht ht[2];
|
||||
long rehashidx; /* rehashing not in progress if rehashidx == -1 */
|
||||
unsigned long iterators; /* number of iterators currently running */
|
||||
} dict;
|
||||
```
|
||||
|
||||
rehash 操作不是一次性完成,而是采用渐进方式,这是为了避免一次性执行过多的 rehash 操作给服务器带来过大的负担。
|
||||
|
||||
渐进式 rehash 通过记录 dict 的 rehashidx 完成,它从 0 开始然后每执行一次 rehash 都会递增。例如在一次 rehash 中,要把 dict[0] rehash 到 dict[1],这一次会把 dict[0] 上 table[rehashidx] 的键值对 rehash 到 dict[1] 上,dict[0] 的 table[rehashidx] 指向 null,并令 rehashidx++。
|
||||
渐进式 rehash 通过记录 dict 的 rehashidx 完成,它从 0 开始,然后每执行一次 rehash 都会递增。例如在一次 rehash 中,要把 dict[0] rehash 到 dict[1],这一次会把 dict[0] 上 table[rehashidx] 的键值对 rehash 到 dict[1] 上,dict[0] 的 table[rehashidx] 指向 null,并令 rehashidx++。
|
||||
|
||||
在 rehash 期间,每次对字典执行添加、删除、查找或者更新操作时,都会执行一次渐进式 rehash。
|
||||
|
||||
@ -320,13 +320,13 @@ int dictRehash(dict *d, int n) {
|
||||
|
||||
<div align="center"> <img src="../pics//beba612e-dc5b-4fc2-869d-0b23408ac90a.png"/> </div><br>
|
||||
|
||||
在查找时,从上层指针开始查找,找到对应的区间之后再到下一层去查找。例如下图演示了查找 22 的过程。
|
||||
在查找时,从上层指针开始查找,找到对应的区间之后再到下一层去查找。下图演示了查找 22 的过程。
|
||||
|
||||
<div align="center"> <img src="../pics//0ea37ee2-c224-4c79-b895-e131c6805c40.png"/> </div><br>
|
||||
|
||||
与红黑树等平衡树相比,跳跃表具有以下优点:
|
||||
|
||||
- 插入速度非常快速,因为不需要平衡树的旋转操作;
|
||||
- 插入速度非常快速,因为不需要进行旋转等操作来维护平衡性;
|
||||
- 更容易实现;
|
||||
- 支持无锁操作。
|
||||
|
||||
@ -336,7 +336,7 @@ int dictRehash(dict *d, int n) {
|
||||
|
||||
可以对 String 进行自增自减运算,从而实现计数器功能。
|
||||
|
||||
例如对于网站访问量,如果使用 MySQL 数据库进行存储,那么每访问一次网站就要对磁盘进行读写操作。而对 Redis 这种内存型数据库的读写性能非常高,很适合存储这种频繁读写的计数量。
|
||||
Redis 这种内存型数据库的读写性能非常高,很适合存储频繁读写的计数量。
|
||||
|
||||
## 缓存
|
||||
|
||||
@ -346,7 +346,7 @@ int dictRehash(dict *d, int n) {
|
||||
|
||||
例如 DNS 记录就很适合使用 Redis 进行存储。
|
||||
|
||||
查找表和缓存类似,也是利用了 Redis 快速的查找特性。但是查找表的内容不能失效,而缓存的内容可以失效。
|
||||
查找表和缓存类似,也是利用了 Redis 快速的查找特性。但是查找表的内容不能失效,而缓存的内容可以失效,因为缓存不作为可靠的数据来源。
|
||||
|
||||
## 消息队列
|
||||
|
||||
@ -356,27 +356,29 @@ List 是一个双向链表,可以通过 lpop 和 lpush 写入和读取消息
|
||||
|
||||
## 会话缓存
|
||||
|
||||
在分布式场景下具有多个应用服务器,可以使用 Redis 来统一存储这些应用服务器的会话信息,使得某个应用服务器宕机时不会丢失会话信息,从而保证高可用。
|
||||
在分布式场景下具有多个应用服务器,可以使用 Redis 来统一存储这些应用服务器的会话信息。
|
||||
|
||||
当应用服务器不再存储用户的会话信息,也就不再具有状态,一个用户可以请求任意一个应用服务器。
|
||||
|
||||
## 分布式锁实现
|
||||
|
||||
在分布式场景下,无法使用单机环境下的锁实现。当多个节点上的进程都需要获取同一个锁时,就需要使用分布式锁来进行同步。
|
||||
在分布式场景下,无法使用单机环境下的锁来对多个节点上的进程进行同步。
|
||||
|
||||
除了可以使用 Redis 自带的 SETNX 命令实现分布式锁之外,还可以使用官方提供的 RedLock 分布式锁实现。
|
||||
可以使用 Reids 自带的 SETNX 命令实现分布式锁,除此之外,还可以使用官方提供的 RedLock 分布式锁实现。
|
||||
|
||||
## 其它
|
||||
|
||||
Set 可以实现交集、并集等操作,例如共同好友功能。
|
||||
Set 可以实现交集、并集等操作,从而实现共同好友等功能。
|
||||
|
||||
ZSet 可以实现有序性操作,例如排行榜功能。
|
||||
ZSet 可以实现有序性操作,从而实现排行榜等功能。
|
||||
|
||||
# 五、Redis 与 Memcached
|
||||
|
||||
两者都是非关系型内存键值数据库。有以下主要不同:
|
||||
两者都是非关系型内存键值数据库,主要有以下不同:
|
||||
|
||||
## 数据类型
|
||||
|
||||
Memcached 仅支持字符串类型,而 Redis 支持五种不同种类的数据类型,使得它可以更灵活地解决问题。
|
||||
Memcached 仅支持字符串类型,而 Redis 支持五种不同的数据类型,可以更灵活地解决问题。
|
||||
|
||||
## 数据持久化
|
||||
|
||||
@ -384,15 +386,15 @@ Redis 支持两种持久化策略:RDB 快照和 AOF 日志,而 Memcached 不
|
||||
|
||||
## 分布式
|
||||
|
||||
Memcached 不支持分布式,只能通过在客户端使用一致性哈希这样的分布式算法来实现分布式存储,这种方式在存储和查询时都需要先在客户端计算一次数据所在的节点。
|
||||
Memcached 不支持分布式,只能通过在客户端使用一致性哈希来实现分布式存储,这种方式在存储和查询时都需要先在客户端计算一次数据所在的节点。
|
||||
|
||||
Redis Cluster 实现了分布式的支持。
|
||||
|
||||
## 内存管理机制
|
||||
|
||||
在 Redis 中,并不是所有数据都一直存储在内存中,可以将一些很久没用的 value 交换到磁盘。而 Memcached 的数据则会一直在内存中。
|
||||
- 在 Redis 中,并不是所有数据都一直存储在内存中,可以将一些很久没用的 value 交换到磁盘,而 Memcached 的数据则会一直在内存中。
|
||||
|
||||
Memcached 将内存分割成特定长度的块来存储数据,以完全解决内存碎片的问题,但是这种方式会使得内存的利用率不高,例如块的大小为 128 bytes,只存储 100 bytes 的数据,那么剩下的 28 bytes 就浪费掉了。
|
||||
- Memcached 将内存分割成特定长度的块来存储数据,以完全解决内存碎片的问题,但是这种方式会使得内存的利用率不高,例如块的大小为 128 bytes,只存储 100 bytes 的数据,那么剩下的 28 bytes 就浪费掉了。
|
||||
|
||||
# 六、键的过期时间
|
||||
|
||||
@ -402,7 +404,9 @@ Redis 可以为每个键设置过期时间,当键过期时,会自动删除
|
||||
|
||||
# 七、数据淘汰策略
|
||||
|
||||
可以设置内存最大使用量,当内存使用量超过时施行淘汰策略,具体有 6 种淘汰策略。
|
||||
可以设置内存最大使用量,当内存使用量超出时,会施行数据淘汰策略。
|
||||
|
||||
Reids 具体有 6 种淘汰策略:
|
||||
|
||||
| 策略 | 描述 |
|
||||
| :--: | :--: |
|
||||
@ -413,15 +417,15 @@ Redis 可以为每个键设置过期时间,当键过期时,会自动删除
|
||||
| allkeys-random | 从所有数据集中任意选择数据进行淘汰 |
|
||||
| noeviction | 禁止驱逐数据 |
|
||||
|
||||
如果使用 Redis 来缓存数据时,要保证所有数据都是热点数据,可以将内存最大使用量设置为热点数据占用的内存量,然后启用 allkeys-lru 淘汰策略,将最近最少使用的数据淘汰。
|
||||
作为内存数据库,出于对性能和内存消耗的考虑,Redis 的淘汰算法实际实现上并非针对所有 key,而是抽样一小部分 key 从中选出被淘汰 key。
|
||||
|
||||
作为内存数据库,出于对性能和内存消耗的考虑,Redis 的淘汰算法(LRU、TTL)实际实现上并非针对所有 key,而是抽样一小部分 key 从中选出被淘汰 key。
|
||||
使用 Redis 缓存数据时,为了提高缓存命中率,需要保证缓存数据都是热点数据。可以将内存最大使用量设置为热点数据占用的内存量,然后启用 allkeys-lru 淘汰策略,将最近最少使用的数据淘汰。
|
||||
|
||||
# 八、持久化
|
||||
|
||||
Redis 是内存型数据库,为了保证数据在断电后不会丢失,需要将内存中的数据持久化到硬盘上。
|
||||
|
||||
## 快照持久化
|
||||
## RDB 持久化
|
||||
|
||||
将某个时间点的所有数据都存放到硬盘上。
|
||||
|
||||
@ -435,9 +439,7 @@ Redis 是内存型数据库,为了保证数据在断电后不会丢失,需
|
||||
|
||||
将写命令添加到 AOF 文件(Append Only File)的末尾。
|
||||
|
||||
对硬盘的文件进行写入时,写入的内容首先会被存储到缓冲区,然后由操作系统决定什么时候将该内容同步到硬盘,用户可以调用 file.flush() 方法请求操作系统尽快将缓冲区存储的数据同步到硬盘。可以看出写入文件的数据不会立即同步到硬盘上,在将写命令添加到 AOF 文件时,要根据需求来保证何时同步到硬盘上。
|
||||
|
||||
有以下同步选项:
|
||||
使用 AOF 持久化需要设置同步选项,从而确保写命令什么时候会同步到磁盘文件上。这是因为对硬盘的文件进行写入并不会马上将内容同步到磁盘文件上,而是先存储到缓冲区,然后由操作系统决定什么时候同步到硬盘。有以下同步选项:
|
||||
|
||||
| 选项 | 同步频率 |
|
||||
| :--: | :--: |
|
||||
|
@ -613,6 +613,8 @@ public int RectCover(int n) {
|
||||
|
||||
因为 h 的赋值表达式为 h = m,因此循环体的循环条件应该为 l < h,详细解释请见 [Leetcode 题解](https://github.com/CyC2018/Interview-Notebook/blob/master/notes/Leetcode%20%E9%A2%98%E8%A7%A3.md#%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE) 二分查找部分。
|
||||
|
||||
但是如果出现 nums[l] == nums[m] == nums[h],那么此时无法确定解在哪个区间,因此需要切换到顺序查找。
|
||||
|
||||
复杂度:O(logN) + O(1)
|
||||
|
||||
```java
|
||||
@ -622,13 +624,22 @@ public int minNumberInRotateArray(int[] nums) {
|
||||
int l = 0, h = nums.length - 1;
|
||||
while (l < h) {
|
||||
int m = l + (h - l) / 2;
|
||||
if (nums[m] <= nums[h])
|
||||
if (nums[l] == nums[m] && nums[m] == nums[h])
|
||||
return minNumber(nums, l, h);
|
||||
else if (nums[m] <= nums[h])
|
||||
h = m;
|
||||
else
|
||||
l = m + 1;
|
||||
}
|
||||
return nums[l];
|
||||
}
|
||||
|
||||
private int minNumber(int[] nums, int l, int h) {
|
||||
for (int i = l; i < h; i++)
|
||||
if (nums[i] > nums[i + 1])
|
||||
return nums[i + 1];
|
||||
return nums[l];
|
||||
}
|
||||
```
|
||||
|
||||
# 12. 矩阵中的路径
|
||||
@ -2022,7 +2033,7 @@ public int getDigitAtIndex(int index)
|
||||
{
|
||||
if (index < 0)
|
||||
return -1;
|
||||
int place = 1; // 位数,1 表示个位,2 表示 十位...
|
||||
int place = 1; // 1 表示个位,2 表示 十位...
|
||||
while (true) {
|
||||
int amount = getAmountOfPlace(place);
|
||||
int totalAmount = amount * place;
|
||||
@ -2640,7 +2651,7 @@ private void swap(char[] c, int i, int j)
|
||||
|
||||
## 解题思路
|
||||
|
||||
将 "abcXYZdef" 旋转左移三位,可以先将 "abc" 和 "XYZdef" 分别旋转,得到 "cbafedZYX",然后再把整个字符串旋转得到 "XYZdefabc"。
|
||||
先将 "abc" 和 "XYZdef" 分别翻转,得到 "cbafedZYX",然后再把整个字符串翻转得到 "XYZdefabc"。
|
||||
|
||||
```java
|
||||
public String LeftRotateString(String str, int n)
|
||||
|
@ -352,7 +352,7 @@ end monitor;
|
||||
|
||||
管程引入了 **条件变量** 以及相关的操作:**wait()** 和 **signal()** 来实现同步操作。对条件变量执行 wait() 操作会导致调用进程阻塞,把管程让出来给另一个进程持有。signal() 操作用于唤醒被阻塞的进程。
|
||||
|
||||
<font size=3> **使用管程实现生成者-消费者问题** </font><br>
|
||||
<font size=3> **使用管程实现生产者-消费者问题** </font><br>
|
||||
|
||||
```pascal
|
||||
// 管程
|
||||
|
@ -139,25 +139,17 @@
|
||||
|
||||
- **物理层** :考虑的是怎样在传输媒体上传输数据比特流,而不是指具体的传输媒体。物理层的作用是尽可能屏蔽传输媒体和通信手段的差异,使数据链路层感觉不到这些差异。
|
||||
|
||||
### 2. 七层协议
|
||||
### 2. OSI
|
||||
|
||||
其中表示层和会话层用途如下:
|
||||
|
||||
- **表示层** :数据压缩、加密以及数据描述。这使得应用程序不必担心在各台主机中表示/存储的内部格式不同的问题。
|
||||
- **表示层** :数据压缩、加密以及数据描述,这使得应用程序不必担心在各台主机中数据内部格式不同的问题。
|
||||
|
||||
- **会话层** :建立及管理会话。
|
||||
|
||||
五层协议没有表示层和会话层,而是将这些功能留给应用程序开发者处理。
|
||||
|
||||
### 3. 数据在各层之间的传递过程
|
||||
|
||||
在向下的过程中,需要添加下层协议所需要的首部或者尾部,而在向上的过程中不断拆开首部和尾部。
|
||||
|
||||
路由器只有下面三层协议,因为路由器位于网络核心中,不需要为进程或者应用程序提供服务,因此也就不需要运输层和应用层。
|
||||
|
||||
<div align="center"> <img src="../pics//ac106e7e-489a-4082-abd9-dabebe48394c.jpg" width="800"/> </div><br>
|
||||
|
||||
### 4. TCP/IP
|
||||
### 3. TCP/IP
|
||||
|
||||
它只有四层,相当于五层协议中数据链路层和物理层合并为网络接口层。
|
||||
|
||||
@ -169,6 +161,14 @@ TCP/IP 协议族是一种沙漏形状,中间小两边大,IP 协议在其中
|
||||
|
||||
<div align="center"> <img src="../pics//d4eef1e2-5703-4ca4-82ab-8dda93d6b81f.png" width="500"/> </div><br>
|
||||
|
||||
### 4. 数据在各层之间的传递过程
|
||||
|
||||
在向下的过程中,需要添加下层协议所需要的首部或者尾部,而在向上的过程中不断拆开首部和尾部。
|
||||
|
||||
路由器只有下面三层协议,因为路由器位于网络核心中,不需要为进程或者应用程序提供服务,因此也就不需要运输层和应用层。
|
||||
|
||||
<div align="center"> <img src="../pics//ac106e7e-489a-4082-abd9-dabebe48394c.jpg" width="800"/> </div><br>
|
||||
|
||||
# 二、物理层
|
||||
|
||||
## 通信方式
|
||||
|
BIN
other/10072416.jpg
Normal file
After Width: | Height: | Size: 25 KiB |
BIN
other/15684156.jpg
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
other/18458140.jpg
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
other/21679154.png
Normal file
After Width: | Height: | Size: 35 KiB |
BIN
other/22954582.jpg
Normal file
After Width: | Height: | Size: 26 KiB |
BIN
other/7719370.png
Normal file
After Width: | Height: | Size: 155 KiB |
BIN
other/8018776.jpg
Normal file
After Width: | Height: | Size: 9.4 KiB |
BIN
other/LogoMakr_0zpEzN.png
Normal file
After Width: | Height: | Size: 33 KiB |