1
0
mirror of https://github.com/Snailclimb/JavaGuide synced 2025-06-16 18:10:13 +08:00

Merge pull request #2 from Snailclimb/master

merge
This commit is contained in:
patrick_zhou 2020-04-08 15:22:43 +08:00 committed by GitHub
commit 912a72f34d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 218 additions and 67 deletions

View File

@ -113,6 +113,8 @@ Github用户如果访问速度缓慢的话可以转移到[码云](https://git
### 并发
**[多线程学习指南](./docs/java/Multithread/多线程学习指南.md)**
**面试题总结:**
1. **[Java 并发基础常见面试题总结](docs/java/Multithread/JavaConcurrencyBasicsCommonInterviewQuestionsSummary.md)**
@ -361,7 +363,6 @@ SSO(Single Sign On)即单点登录说的是用户登陆多个子系统的其中
5. **[【备战面试5】如果面试官问你“你有什么问题问我吗”时你该如何回答](docs/essential-content-for-interview/PreparingForInterview/面试官-你有什么问题要问我.md)**
6. [【备战面试6】应届生面试最爱问的几道 Java 基础问题](docs/essential-content-for-interview/PreparingForInterview/应届生面试最爱问的几道Java基础问题.md)
7. **[【备战面试6】美团面试常见问题总结(附详解答案)](docs/essential-content-for-interview/PreparingForInterview/美团面试常见问题总结.md)**
8. **[【备战面试7】一些刁难的面试问题总结](https://xiaozhuanlan.com/topic/9056431872)**
## Java学习常见问题汇总

View File

@ -35,6 +35,14 @@
**Redis** 有 5 种基础数据结构,它们分别是:**string(字符串)**、**list(列表)**、**hash(字典)**、**set(集合)** 和 **zset(有序集合)**。这 5 种是 Redis 相关知识中最基础、最重要的部分,下面我们结合源码以及一些实践来给大家分别讲解一下。
注意:
> 每种数据结构都有自己底层的内部编码实现而且是多种实现这样Redis会在合适的场景选择合适的内部编码。
>
> 可以看到每种数据结构都有两种以上的内部编码实现例如string数据结构就包含了raw、int和embstr三种内部编码。
>
> 同时有些内部编码可以作为多种外部数据结构的内部实现例如ziplist就是hash、list和zset共有的内部编码。
## 1字符串 string
Redis 中的字符串是一种 **动态字符串**,这意味着使用者可以修改,它的底层实现有点类似于 Java 中的 **ArrayList**,有一个字符数组,从源码的 **sds.h/sdshdr 文件** 中可以看到 Redis 底层对于字符串的定义 **SDS**,即 *Simple Dynamic String* 结构:
@ -376,7 +384,7 @@ typedef struct dictEntry {
hash 也有缺点hash 结构的存储消耗要高于单个字符串,所以到底该使用 hash 还是字符串,需要根据实际情况再三权衡:
```console
```shell
> HSET books java "think in java" # 命令行的字符串如果包含空格则需要使用引号包裹
(integer) 1
> HSET books python "python cookbook"
@ -402,7 +410,7 @@ Redis 的集合相当于 Java 语言中的 **HashSet**,它内部的键值对
由于该结构比较简单,我们直接来看看是如何使用的:
```console
```shell
> SADD books java
(integer) 1
> SADD books java # 重复
@ -483,10 +491,19 @@ Redis 的集合相当于 Java 语言中的 **HashSet**,它内部的键值对
# 扩展/相关阅读
### 优秀文章
1. 阿里云 Redis 开发规范 - [https://www.infoq.cn/article/K7dB5AFKI9mr5Ugbs_px](https://www.infoq.cn/article/K7dB5AFKI9mr5Ugbs_px)
2. 为什么要防止 bigkey - [https://mp.weixin.qq.com/s?__biz=Mzg2NTEyNzE0OA==&mid=2247483677&idx=1&sn=5c320b46f0e06ce9369a29909d62b401&chksm=ce5f9e9ef928178834021b6f9b939550ac400abae5c31e1933bafca2f16b23d028cc51813aec&scene=21#wechat_redirect](https://mp.weixin.qq.com/s?__biz=Mzg2NTEyNzE0OA==&mid=2247483677&idx=1&sn=5c320b46f0e06ce9369a29909d62b401&chksm=ce5f9e9ef928178834021b6f9b939550ac400abae5c31e1933bafca2f16b23d028cc51813aec&scene=21#wechat_redirect)
3. Redis【入门】就这一篇 - [https://www.wmyskxz.com/2018/05/31/redis-ru-men-jiu-zhe-yi-pian/](https://www.wmyskxz.com/2018/05/31/redis-ru-men-jiu-zhe-yi-pian/)
#### Redis数据结构源码分析
1. Redis 数据结构-字符串源码分析:[https://my.oschina.net/mengyuankan/blog/1926320](https://my.oschina.net/mengyuankan/blog/1926320)
2. Redis 数据结构-字典源码分析: [https://my.oschina.net/mengyuankan/blog/1929593](https://my.oschina.net/mengyuankan/blog/1929593)
# 参考资料
1. 《Redis 设计与实现》 - [http://redisbook.com/](http://redisbook.com/)

View File

@ -119,3 +119,4 @@
- 冷熊简历(MarkDown在线简历工具可在线预览、编辑和生成PDF):<http://cv.ftqq.com/>
- Typora+[Java程序员简历模板](https://github.com/geekcompany/ResumeSample/blob/master/java.md)
- Guide哥自己写的Markdown模板[https://github.com/Snailclimb/typora-markdown-resume](https://github.com/Snailclimb/typora-markdown-resume)

View File

@ -131,7 +131,7 @@ public class MultiThread {
## 5. 使用多线程可能带来什么问题?
并发编程的目的就是为了能提高程序的执行效率提高程序运行速度,但是并发编程并不总是能提高程序运行速度的,而且并发编程可能会遇到很多问题,比如:内存泄漏、上下文切换、死锁还有受限于硬件和软件的资源闲置问题
并发编程的目的就是为了能提高程序的执行效率提高程序运行速度,但是并发编程并不总是能提高程序运行速度的,而且并发编程可能会遇到很多问题,比如:内存泄漏、死锁、线程不安全等等
## 6. 说说线程的生命周期和状态?

View File

@ -1,3 +1,4 @@
<!-- TOC -->
- [一 使用线程池的好处](#一-使用线程池的好处)
@ -28,7 +29,7 @@
- [5.2 SingleThreadExecutor 详解](#52-singlethreadexecutor-详解)
- [5.2.1 介绍](#521-介绍)
- [5.2.2 执行任务过程介绍](#522-执行任务过程介绍)
- [5.2.3 为什么不推荐使用`FixedThreadPool`](#523-为什么不推荐使用fixedthreadpool)
- [5.2.3 为什么不推荐使用`SingleThreadExecutor`](#523-为什么不推荐使用singlethreadexecutor)
- [5.3 CachedThreadPool 详解](#53-cachedthreadpool-详解)
- [5.3.1 介绍](#531-介绍)
- [5.3.2 执行任务过程介绍](#532-执行任务过程介绍)
@ -43,6 +44,7 @@
<!-- /TOC -->
## 一 使用线程池的好处
> **池化技术相比大家已经屡见不鲜了线程池、数据库连接池、Http 连接池等等都是对这个思想的应用。池化技术的思想主要是为了减少每次获取资源的消耗,提高对资源的利用率。**
@ -163,7 +165,7 @@ public class ScheduledThreadPoolExecutor
3. **`threadFactory`** :executor 创建新线程的时候会用到。
4. **`handler`** :饱和策略。关于饱和策略下面单独介绍一下。
下面这张图可以加深你对线程池中各个参数的相互关系的理解图片来源《Java性能调优实战》
下面这张图可以加深你对线程池中各个参数的相互关系的理解图片来源《Java 性能调优实战》):
![线程池各个参数的关系](https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/2019-7/线程池各个参数的关系.jpg)
@ -650,7 +652,7 @@ Wed Nov 13 13:40:43 CST 2019::pool-1-thread-5
1. 如果当前运行的线程数少于 corePoolSize则创建一个新的线程执行任务
2. 当前线程池中有一个运行的线程后,将任务加入 `LinkedBlockingQueue`
3. 线程执行完当前的任务后,会在循环中反复从` LinkedBlockingQueue` 中获取任务来执行;
3. 线程执行完当前的任务后,会在循环中反复从`LinkedBlockingQueue` 中获取任务来执行;
#### 5.2.3 为什么不推荐使用`SingleThreadExecutor`
@ -683,7 +685,7 @@ Wed Nov 13 13:40:43 CST 2019::pool-1-thread-5
}
```
`CachedThreadPool`` corePoolSize` 被设置为空0`maximumPoolSize `被设置为 Integer.MAX.VALUE即它是无界的这也就意味着如果主线程提交任务的速度高于 `maximumPool` 中线程处理任务的速度时,`CachedThreadPool` 会不断创建新的线程。极端情况下,这样会导致耗尽 cpu 和内存资源。
`CachedThreadPool``corePoolSize` 被设置为空0`maximumPoolSize`被设置为 Integer.MAX.VALUE即它是无界的这也就意味着如果主线程提交任务的速度高于 `maximumPool` 中线程处理任务的速度时,`CachedThreadPool` 会不断创建新的线程。极端情况下,这样会导致耗尽 cpu 和内存资源。
#### 5.3.2 执行任务过程介绍
@ -695,13 +697,13 @@ Wed Nov 13 13:40:43 CST 2019::pool-1-thread-5
1. 首先执行 `SynchronousQueue.offer(Runnable task)` 提交任务到任务队列。如果当前 `maximumPool` 中有闲线程正在执行 `SynchronousQueue.poll(keepAliveTime,TimeUnit.NANOSECONDS)`,那么主线程执行 offer 操作与空闲线程执行的 `poll` 操作配对成功,主线程把任务交给空闲线程执行,`execute()`方法执行完成,否则执行下面的步骤 2
2. 当初始 `maximumPool` 为空,或者 `maximumPool` 中没有空闲线程时,将没有线程执行 `SynchronousQueue.poll(keepAliveTime,TimeUnit.NANOSECONDS)`。这种情况下,步骤 1 将失败,此时 `CachedThreadPool` 会创建新线程执行任务execute 方法执行完成;
#### 5.3.3 为什么不推荐使用`CachedThreadPool`
#### 5.3.3 为什么不推荐使用`CachedThreadPool`
`CachedThreadPool`允许创建的线程数量为 Integer.MAX_VALUE ,可能会创建大量线程,从而导致 OOM。
## 六 ScheduledThreadPoolExecutor 详解
**`ScheduledThreadPoolExecutor` 主要用来在给定的延迟后运行任务,或者定期执行任务。** 这个在实际项目中基本不会被用到所以对这部分大家只需要简单了解一下它的思想。关于如何在Spring Boot 中 实现定时任务,可以查看这篇文章[《5分钟搞懂如何在Spring Boot中Schedule Tasks》](https://github.com/Snailclimb/springboot-guide/blob/master/docs/advanced/SpringBoot-ScheduleTasks.md)。
**`ScheduledThreadPoolExecutor` 主要用来在给定的延迟后运行任务,或者定期执行任务。** 这个在实际项目中基本不会被用到,所以对这部分大家只需要简单了解一下它的思想。关于如何在 Spring Boot 中 实现定时任务,可以查看这篇文章[《5 分钟搞懂如何在 Spring Boot Schedule Tasks》](https://github.com/Snailclimb/springboot-guide/blob/master/docs/advanced/SpringBoot-ScheduleTasks.md)。
### 6.1 简介
@ -726,7 +728,7 @@ Wed Nov 13 13:40:43 CST 2019::pool-1-thread-5
1. 当调用 `ScheduledThreadPoolExecutor`**`scheduleAtFixedRate()`** 方法或者**`scheduleWirhFixedDelay()`** 方法时,会向 `ScheduledThreadPoolExecutor`**`DelayQueue`** 添加一个实现了 **`RunnableScheduledFuture`** 接口的 **`ScheduledFutureTask`** 。
2. 线程池中的线程从 `DelayQueue` 中获取 `ScheduledFutureTask`,然后执行任务。
**`ScheduledThreadPoolExecutor` 为了实现周期性的执行任务,对 `ThreadPoolExecutor `做了如下修改:**
**`ScheduledThreadPoolExecutor` 为了实现周期性的执行任务,对 `ThreadPoolExecutor`做了如下修改:**
- 使用 **`DelayQueue`** 作为任务队列;
- 获取任务的方不同
@ -736,38 +738,40 @@ Wed Nov 13 13:40:43 CST 2019::pool-1-thread-5
![ScheduledThreadPoolExecutor执行周期任务的步骤](https://imgconvert.csdnimg.cn/aHR0cDovL215LWJsb2ctdG8tdXNlLm9zcy1jbi1iZWlqaW5nLmFsaXl1bmNzLmNvbS8xOC01LTMwLzU5OTE2Mzg5LmpwZw?x-oss-process=image/format,png)
1. 线程 1 从 `DelayQueue` 中获取已到期的 `ScheduledFutureTaskDelayQueue.take()`。到期任务是指 `ScheduledFutureTask `的 time 大于等于当前系统的时间;
1. 线程 1 从 `DelayQueue` 中获取已到期的 `ScheduledFutureTaskDelayQueue.take()`。到期任务是指 `ScheduledFutureTask`的 time 大于等于当前系统的时间;
2. 线程 1 执行这个 `ScheduledFutureTask`
3. 线程 1 修改 `ScheduledFutureTask` 的 time 变量为下次将要被执行的时间;
4. 线程 1 把这个修改 time 之后的 `ScheduledFutureTask` 放回 `DelayQueue` 中(`DelayQueue.add()`)。
## 七 线程池大小确定
**线程池数量的确定一直是困扰着程序员的一个难题,大部分程序员在设定线程池大小的时候就是随心而定。我们并没有考虑过这样大小的配置是否会带来什么问题,我自己就是这大部分程序员中的一个代表。**
**线程池数量的确定一直是困扰着程序员的一个难题,大部分程序员在设定线程池大小的时候就是随心而定。**
由于笔主对如何确定线程池大小也没有什么实际经验,所以,这部分内容参考了网上很多文章/书籍。
**首先,可以肯定的一点是线程池大小设置过大或者过小都会有问题。合适的才是最好,貌似在 95 % 的场景下都是合适的。**
如果阅读过我的上一篇关于线程池的文章的话,你一定知道:
**如果我们设置的线程池数量太小的话,如果同一时间有大量任务/请求需要处理,可能会导致大量的请求/任务在任务队列中排队等待执行,甚至会出现任务队列满了之后任务/请求无法处理的情况,或者大量任务堆积在任务队列导致 OOM。这样很明显是有问题的 CPU 根本没有得到充分利用。**
**但是,如果我们设置线程数量太大,大量线程可能会同时在争取 CPU 资源,这样会导致大量的上下文切换,从而增加线程的执行时间,影响了整体执行效率。**
很多人甚至可能都会觉得把线程池配置过大一点比较好!我觉得这明显是有问题的。就拿我们生活中非常常见的一例子来说:**并不是人多就能把事情做好,增加了沟通交流成本。你本来一件事情只需要 3 个人做,你硬是拉来了 6 个人,会提升做事效率嘛?我想并不会。** 线程数量过多的影响也是和我们分配多少人做事情一样,对于多线程这个场景来说主要是增加了**上下文切换**成本。不清楚什么是上下文切换的话,可以看我下面的介绍。
> 上下文切换:
>
> 多线程编程中一般线程的个数都大于 CPU 核心的个数,而一个 CPU 核心在任意时刻只能被一个线程使用为了让这些线程都能得到有效执行CPU 采取的策略是为每个线程分配时间片并轮转的形式。当一个线程的时间片用完的时候就会重新处于就绪状态让给其他线程使用,这个过程就属于一次上下文切换。概括来说就是:当前任务在执行完 CPU 时间片切换到另一个任务之前会先保存自己的状态,以便下次再切换回这个任务时,可以再加载这个任务的状态。**任务从保存到再加载的过程就是一次上下文切换**。
>
> 上下文切换通常是计算密集型的。也就是说,它需要相当可观的处理器时间,在每秒几十上百次的切换中,每次切换都需要纳秒量级的时间。所以,上下文切换对系统来说意味着消耗大量的 CPU 时间,事实上,可能是操作系统中时间消耗最大的操作。
> 上下文切换通常是计算密集型的。也就是说,它需要相当可观的处理器时间,在每秒几十上百次的切换中,每次切换都需要纳秒量级的时间。所以,上下文切换对系统来说意味着消耗大量的 CPU 时间,事实上,可能是操作系统中时间消耗最大的操作。
>
> Linux 相比与其他操作系统(包括其他类 Unix 系统)有很多的优点,其中有一项就是,其上下文切换和模式切换的时间消耗非常少。
**类比于实现世界中的人类通过合作做某件事情,我们可以肯定的一点是线程池大小设置过大或者过小都会有问题,合适的才是最好。**
**如果我们设置的线程池数量太小的话,如果同一时间有大量任务/请求需要处理,可能会导致大量的请求/任务在任务队列中排队等待执行,甚至会出现任务队列满了之后任务/请求无法处理的情况,或者大量任务堆积在任务队列导致 OOM。这样很明显是有问题的 CPU 根本没有得到充分利用。**
**但是,如果我们设置线程数量太大,大量线程可能会同时在争取 CPU 资源,这样会导致大量的上下文切换,从而增加线程的执行时间,影响了整体执行效率。**
有一个简单并且适用面比较广的公式:
- **CPU 密集型任务(N+1)** 这种任务消耗的主要是 CPU 资源,可以将线程数设置为 NCPU 核心数)+1比 CPU 核心数多出来的一个线程是为了防止线程偶发的缺页中断或者其它原因导致的任务暂停而带来的影响。一旦任务暂停CPU 就会处于空闲状态,而在这种情况下多出来的一个线程就可以充分利用 CPU 的空闲时间。
- **I/O 密集型任务(2N)** 这种任务应用起来,系统会用大部分的时间来处理 I/O 交互,而线程在处理 I/O 的时间段内不会占用 CPU 来处理,这时就可以将 CPU 交出给其它线程使用。因此在 I/O 密集型任务的应用中,我们可以多配置一些线程,具体的计算方法是 2N。
**如何判断是 CPU 密集任务还是 IO 密集任务?**
CPU 密集型简单理解就是利用 CPU 计算能力的任务比如你在内存中对大量数据进行排序。单凡涉及到网络读取,文件读取这类都是 IO 密集型,这类任务的特点是 CPU 计算耗费时间相比于等待 IO 操作完成的时间来说很少,大部分时间都花在了等待 IO 操作完成上。
## 八 参考
- 《Java 并发编程的艺术》

View File

@ -0,0 +1,158 @@
## 前言
这是我的第二篇专门介绍如何去学习某个知识点的文章,在上一篇[《写给 Java 程序员看的算法学习指南!》](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247486508&idx=1&sn=ce2faafcde166d5412d7166a01fdc1e9&chksm=cea243e7f9d5caf1dbf4d6ccf0438a1731bc0070310bba1ac481d485e4a6756349c20f02a6b1&token=211950660&lang=zh_CN#rd) 的文章中,我推荐了一些关于 **算法学习的书籍以及资源**
相比于写技术文章来说,写这种这种类型的文章实际花费的时间可能会稍微少一点。但是,这种学习指南形式的文章,我想对于 Java 初学者甚至是工作几年的 Java 工程师来说应该还是非常有帮助的!
我们都知道多线程应该是大部分 Java 程序员最难啃的一块骨头之一,这部分内容的难度跨度大,难实践,并且市面上的参考资料的质量也层次不齐。
在这篇文章中,我会首先介绍一下 **Java 多线程学习** 中比较重要的一些问题,然后还会推荐一些比较不错的学习资源供大家参考。希望对你们学习多线程相关的知识能有帮助。以下介绍的很多知识点你都可以在这里找到:[https://snailclimb.gitee.io/javaguide/#/?id=并发](https://snailclimb.gitee.io/javaguide/#/?id=并发)
![](https://imgkr.cn-bj.ufileos.com/49f0b564-224d-43d8-813e-0fe53196c1a9.png)
**另外,我还将本文的内容同步到了 Github 上,点击阅读原文即可直达。如果你觉得有任何需要完善和修改的地方,都可以去 Github 给我提交 Issue 或者 PR推荐。**
## 一.Java 多线程知识点总结
### 1.1.多线程基础
1. 什么是线程和进程? 线程与进程的关系,区别及优缺点?
2. 说说并发与并行的区别?
3. 为什么要使用多线程呢?
4. 使用多线程可能带来什么问题?(内存泄漏、死锁、线程不安全等等)
5. 创建线程有哪几种方式a.继承 Thread 类;b.实现 Runnable 接口;c. 使用 Executor 框架;d.使用 FutureTask
6. 说说线程的生命周期和状态?
7. 什么是上下文切换?
8. 什么是线程死锁?如何避免死锁?
9. 说说 sleep() 方法和 wait() 方法区别和共同点?
10. 为什么我们调用 start() 方法时会执行 run() 方法,为什么我们不能直接调用 run() 方法?
11. ......
### 1.2.多线程知识进阶
#### volatile 关键字
1. Java 内存模型(**JMM**;
2. 重排序与 happens-before 原则了解吗?
3. volatile 关键字的作用;
4. 说说 synchronized 关键字和 volatile 关键字的区别;
5. ......
#### ThreadLocal
1. 有啥用(解决了什么问题)?怎么用?
2. 原理了解吗?
3. 内存泄露问题了解吗?
#### 线程池
1. 为什么要用线程池?
2. 你会使用线程池吗?
3. 如何创建线程池比较好? (推荐使用 `ThreadPoolExecutor` 构造函数创建线程池)
4. `ThreadPoolExecutor` 类的重要参数了解吗?`ThreadPoolExecutor` 饱和策略了解吗?
5. 线程池原理了解吗?
6. 几种常见的线程池了解吗?为什么不推荐使用`FixedThreadPool`
7. 如何设置线程池的大小?
8. ......
#### AQS
1. 简介
2. 原理
3. AQS 常用组件。
- **Semaphore(信号量)**-允许多个线程同时访问
- **CountDownLatch (倒计时器)**-CountDownLatch 允许 count 个线程阻塞在一个地方,直至所有线程的任务都执行完毕。
- **CyclicBarrier(循环栅栏)**-CyclicBarrier 和 CountDownLatch 非常类似,它也可以实现线程间的技术等待,但是它的功能比 CountDownLatch 更加复杂和强大。主要应用场景和 CountDownLatch 类似。
- **ReentrantLock 和 ReentrantReadWriteLock**
- ......
#### 锁
锁的常见分类
1. 可重入锁和非可重入锁
2. 公平锁与非公平锁
3. 读写锁和排它锁
**synchronized 关键字**
1. 说一说自己对于 synchronized 关键字的了解;
2. 说说自己是怎么使用 synchronized 关键字,在项目中用到了吗;
3. 讲一下 synchronized 关键字的底层原理;
4. 说说 JDK1.6 之后的 synchronized 关键字底层做了哪些优化,可以详细介绍一下这些优化吗;
5. 谈谈 synchronized 和 ReentrantLock 的区别;
6. ......
**ReentrantLock 和 ReentrantReadWriteLock**
**ReadWriteLock**
**StampedLockJDK8**
#### **Atomic 与 CAS**
**CAS:**
1. 介绍
2. 原理
**Atomic 原子类:**
1. 介绍一下 Atomic 原子类;
2. JUC 包中的原子类是哪 4 类?
3. 讲讲 AtomicInteger 的使用;
4. 能不能给我简单介绍一下 AtomicInteger 类的原理。
5. ......
#### 并发容器
JDK 提供的这些容器大部分在 `java.util.concurrent` 包中。
- **ConcurrentHashMap:** 线程安全的 HashMap
- **CopyOnWriteArrayList:** 线程安全的 List在读多写少的场合性能非常好远远好于 Vector.
- **ConcurrentLinkedQueue:** 高效的并发队列,使用链表实现。可以看做一个线程安全的 LinkedList这是一个非阻塞队列。
- **BlockingQueue:** 这是一个接口JDK 内部通过链表、数组等方式实现了这个接口。表示阻塞队列,非常适合用于作为数据共享的通道。
- **ConcurrentSkipListMap:** 跳表的实现。这是一个 Map使用跳表的数据结构进行快速查找。
- ......
#### Future 和 CompletableFuture
## 二.书籍推荐
#### 《Java 并发编程之美》
![《Java 并发编程之美》](https://imgkr.cn-bj.ufileos.com/b4c03ec2-f907-47a4-ad19-731c969a499b.png)
**我觉得这本书还是非常适合我们用来学习 Java 多线程的。这本书的讲解非常通俗易懂,作者从并发编程基础到实战都是信手拈来。**
另外,这本书的作者加多自身也会经常在网上发布各种技术文章。我觉得这本书也是加多大佬这么多年在多线程领域的沉淀所得的结果吧!他书中的内容基本都是结合代码讲解,非常有说服力!
#### 《实战 Java 高并发程序设计》
![《实战 Java 高并发程序设计》](https://imgkr.cn-bj.ufileos.com/0d6e5484-aea1-41cc-8417-4694c6028012.png)
这个是我第二本要推荐的书籍,比较适合作为多线程入门/进阶书籍来看。这本书内容同样是理论结合实战,对于每个知识点的讲解也比较通俗易懂,整体结构也比较清。
#### 《深入浅出 Java 多线程》
![《深入浅出Java多线程》](https://imgkr.cn-bj.ufileos.com/7001a206-8ac0-432c-bf62-ca7130487c12.png)
这本书是几位大厂如阿里的大佬开源的Github 地址:[https://github.com/RedSpider1/concurrent](https://github.com/RedSpider1/concurrent)
几位作者为了写好《深入浅出 Java 多线程》这本书阅读了大量的 Java 多线程方面的书籍和博客然后再加上他们的经验总结、Demo 实例、源码解析,最终才形成了这本书。
这本书的质量也是非常过硬!给作者们点个赞!这本书有统一的排版规则和语言风格、清晰的表达方式和逻辑。并且每篇文章初稿写完后,作者们就会互相审校,合并到主分支时所有成员会再次审校,最后再通篇修订了三遍。
#### 《Java 并发编程的艺术》
![《Java 并发编程的艺术》](https://imgkr.cn-bj.ufileos.com/9ff63f79-f537-40df-a111-be5a11747b8f.png)
这本书不是很适合作为 Java 多线程入门书籍,需要具备一定的 JVM 基础,有些东西讲的还是挺深入的。另外,就我自己阅读这本书的感觉来说,我觉得这本书的章节规划有点杂乱,但是,具体到某个知识点又很棒!这可能也和这本书由三名作者共同编写完成有关系吧!
**综上:这本书并不是和 Java 多线程入门,你也不需要把这本书的每一章节都看一遍,建议挑选自己想要详细了解的知识点来看。**
## 三.总结
在这篇文章中我主要总结了 Java 多线程方面的知识点并且推荐了相关的书籍。并发这部分东西实战的话比较难你可以尝试学会了某个知识点之后然后在自己写过的一些项目上实践。另外leetcode 有一个练习多线程的类别: [https://leetcode-cn.com/problemset/concurrency](https://leetcode-cn.com/problemset/concurrency) 可以作为参考。
**为了这篇文章的内容更加完善,我还将本文的内容同步到了 Github 上,点击阅读原文即可直达。如果你觉得有任何需要完善和修改的地方,都可以去 Github 给我提交 Issue 或者 PR推荐。**

View File

@ -144,7 +144,7 @@ public class Employee {
u2 this_class;//当前类
u2 super_class;//父类
u2 interfaces_count;//接口
u2 interfaces[interfaces_count];//一个可以实现多个接口
u2 interfaces[interfaces_count];//一个可以实现多个接口
```
**类索引用于确定这个类的全限定名,父类索引用于确定这个类的父类的全限定名,由于 Java 语言的单继承,所以父类索引只有一个,除了 `java.lang.Object` 之外,所有的 java 类都有父类,因此除了 `java.lang.Object` 外,所有 Java 类的父类索引都不为 0。**

View File

@ -1,38 +1,6 @@
<!-- TOC -->
- [一 OSI与TCP/IP各层的结构与功能,都有哪些协议?](#一-osi与tcpip各层的结构与功能都有哪些协议)
- [1.1 应用层](#11-应用层)
- [1.2 运输层](#12-运输层)
- [1.3 网络层](#13-网络层)
- [1.4 数据链路层](#14-数据链路层)
- [1.5 物理层](#15-物理层)
- [1.6 总结一下](#16-总结一下)
- [二 TCP 三次握手和四次挥手(面试常客)](#二-tcp-三次握手和四次挥手面试常客)
- [2.1 TCP 三次握手漫画图解](#21-tcp-三次握手漫画图解)
- [2.2 为什么要三次握手](#22-为什么要三次握手)
- [2.3 为什么要传回 SYN](#23-为什么要传回-syn)
- [2.4 传了 SYN,为啥还要传 ACK](#24-传了-syn为啥还要传-ack)
- [2.5 为什么要四次挥手](#25-为什么要四次挥手)
- [三 TCP,UDP 协议的区别](#三-tcpudp-协议的区别)
- [四 TCP 协议如何保证可靠传输](#四-tcp-协议如何保证可靠传输)
- [4.1 ARQ协议](#41-arq协议)
- [停止等待ARQ协议](#停止等待arq协议)
- [连续ARQ协议](#连续arq协议)
- [4.2 滑动窗口和流量控制](#42-滑动窗口和流量控制)
- [4.3 拥塞控制](#43-拥塞控制)
- [五 在浏览器中输入url地址 ->> 显示主页的过程(面试常客)](#五--在浏览器中输入url地址---显示主页的过程面试常客)
- [六 状态码](#六-状态码)
- [七 各种协议与HTTP协议之间的关系](#七-各种协议与http协议之间的关系)
- [八 HTTP长连接,短连接](#八--http长连接短连接)
- [九 HTTP是不保存状态的协议,如何保存用户状态?](#九-http是不保存状态的协议如何保存用户状态)
- [十 Cookie的作用是什么?和Session有什么区别](#十-cookie的作用是什么和session有什么区别)
- [十一 HTTP 1.0和HTTP 1.1的主要区别是什么?](#十一-http-10和http-11的主要区别是什么)
- [十二 URI和URL的区别是什么?](#十二-uri和url的区别是什么)
- [十三 HTTP 和 HTTPS 的区别?](#十三-http-和-https-的区别)
- [建议](#建议)
- [参考](#参考)
<!-- /TOC -->
## 一 OSI与TCP/IP各层的结构与功能,都有哪些协议?
@ -90,7 +58,7 @@
### 1.6 总结一下
上面我们对计算机网络的五层体系结构有了初步的了解,下面附送一张七层体系结构图总结一下。图片来源https://blog.csdn.net/yaopeng_2005/article/details/7064869
上面我们对计算机网络的五层体系结构有了初步的了解,下面附送一张七层体系结构图总结一下(图片来源于网络)。
![七层体系结构图](https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/2019/7/七层体系结构图.png)

View File

@ -8,11 +8,13 @@
这篇文章只是对一些操作系统比较重要概念的一个概览,深入学习的话,建议大家还是老老实实地去看书。另外, 这篇文章的很多内容参考了《现代操作系统》第三版这本书,非常感谢。
## 一 操作系统基础
面试官顶着蓬松的假发向我走来,只见他一手拿着厚重的 Thinkpad ,一手提着他那淡黄的长裙。
<img src="http://wx4.sinaimg.cn/large/ceeb653ely1gd8wj5evc4j20i00n0dh0.jpg" height="300"></img>
<img src="https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/2019-11/ceeb653ely1gd8wj5evc4j20i00n0dh0.jpg" height="300"></img>
### 1.1 什么是操作系统?
@ -36,7 +38,7 @@
🙋 **我** :介绍系统调用之前,我们先来了解一下用户态和系统态。
<img src="http://ww4.sinaimg.cn/large/006r3PQBjw1fbimb5c3srj30b40b40t9.jpg" height="200" width="2"/>
![](https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/2019-11/006r3PQBjw1fbimb5c3srj30b40b40t9-20200404224750646.jpg)
根据进程访问资源的特点,我们可以把进程在系统上的运行分为两个级别:
@ -151,7 +153,7 @@
🙋 **我** :谢谢面试官!刚刚把这个给忘记了~
<img src="http://ww4.sinaimg.cn/large/6af89bc8gw1f8txoxc2asj20k00k0mxv.jpg" alt="这就很尴尬了_尴尬表情" height="200" width="200"/>
<img src="https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/2019-11/6af89bc8gw1f8txoxc2asj20k00k0mxv.jpg" alt="这就很尴尬了_尴尬表情" height="200" width="200"/>
### 3.3 快表和多级页表
@ -191,7 +193,7 @@
🙋 **我**
<img src="http://wx3.sinaimg.cn/large/de80a5ably1gcuslckpygg208c08cwfu.gif" height="200" width="200"></img>
<img src="https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/2019-11/de80a5ably1gcuslckpygg208c08cwfu.gif" height="200" width="200"></img>
1. **共同点**
- 分页机制和分段机制都是为了提高内存利用率,较少内存碎片。
@ -212,7 +214,7 @@
🙋 **我** :这部分我真不清楚!
<img src="http://wx2.sinaimg.cn/bmiddle/a9cf8ef6ly1fhqpdipcyfj20ce0b4wex.jpg " height="300px" />
<img src="https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/2019-11/a9cf8ef6ly1fhqpdipcyfj20ce0b4wex.jpg .jpeg" height="300px" />
于是面试完之后我默默去查阅了相关文档!留下了没有技术的泪水。。。
@ -316,10 +318,10 @@
当发生缺页中断时,如果当前内存中并没有空闲的页面,操作系统就必须在内存选择一个页面将其移出内存,以便为即将调入的页面让出空间。用来选择淘汰哪一页的规则叫做页面置换算法,我们可以把页面置换算法看成是淘汰页面的规则。
- **OPT 页面置换算法(最佳页面置换算法)** 理想情况,不可能实现,一般作为衡量其他置换算法的方法。
- **FIFO 页面置换算法(先进先出页面置换算法)** : 总是淘汰最先进入内存的页面,即选择在内存中驻留时间最久的页面进行淘汰。
- **LRU 页面置换算法(最近未使用页面置换算法)** LRULeast Currently Used算法赋予每个页面一个访问字段,用来记录一个页面自上次被访问以来所经历的时间 T当须淘汰一个页面时选择现有页面中其 T 值最大的,即最近最久未使用的页面予以淘汰。
- **LFU 页面置换算法(最少使用页面排序算法)** : LFULeast Frequently Used算法会让系统维护一个按最近一次访问时间排序的页面链表链表首节点是最近刚刚使用过的页面链表尾节点是最久未使用的页面。访问内存时找到相应页面并把它移到链表之首。缺页时置换链表尾节点的页面。也就是说内存内使用越频繁的页面被保留的时间也相对越长
- **OPT 页面置换算法(最佳页面置换算法)** 最佳(Optimal, OPT)置换算法所选择的被淘汰页面将是以后永不使用的,或者是在最长时间内不再被访问的页面,这样可以保证获得最低的缺页率。但由于人们目前无法预知进程在内存下的若千页面中哪个是未来最长时间内不再被访问的,因而该算法无法实现。一般作为衡量其他置换算法的方法。
- **FIFOFirst In First Out 页面置换算法(先进先出页面置换算法)** : 总是淘汰最先进入内存的页面,即选择在内存中驻留时间最久的页面进行淘汰。
- **LRU Least Currently Used页面置换算法(最近最久未使用页面置换算法)** LRU算法赋予每个页面一个访问字段用来记录一个页面自上次被访问以来所经历的时间 T当须淘汰一个页面时选择现有页面中其 T 值最大的,即最近最久未使用的页面予以淘汰。
- **LFU Least Frequently Used页面置换算法最少使用页面置换算法** : 该置换算法选择在之前时期使用最少的页面作为淘汰页
## Reference