Skip to content

Commit 5c4e1e1

Browse files
committed
update
1 parent a1bc7c9 commit 5c4e1e1

10 files changed

+815
-857
lines changed

JavaKnowledge/Git简介.md

+376-305
Large diffs are not rendered by default.

JavaKnowledge/HashMap实现原理分析.md

+128-113
Large diffs are not rendered by default.

JavaKnowledge/Http与Https的区别.md

+7-7
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,12 @@ HTTP与HTTPS的区别
3939

4040
你是不是很好奇,当你在浏览器中输入网址后,到底发生了什么事情?你想要的内容是如何展现出来的?让我们通过一个例子来探讨一下,我们假设访问的 URL 地址为 `http://www.someSchool.edu/someDepartment/home.index`,当我们输入网址并点击回车时,浏览器内部会进行如下操作
4141

42-
- DNS服务器会首先进行域名的映射,找到访问`www.someSchool.edu`所在的地址,然后HTTP 客户端进程在 80 端口发起一个到服务器 `www.someSchool.edu` 的 TCP 连接(80 端口是 HTTP 的默认端口)。在客户和服务器进程中都会有一个`套接字`与其相连。
43-
- HTTP 客户端通过它的套接字向服务器发送一个 HTTP 请求报文。该报文中包含了路径 `someDepartment/home.index` 的资源,我们后面会详细讨论 HTTP 请求报文
44-
- HTTP 服务器通过它的套接字接受该报文,进行请求的解析工作,并从其`存储器(RAM 或磁盘)`中检索出对象 [www.someSchool.edu/someDepartment/home.index,然后把检索出来的对象进行封装,封装到](http://www.someSchool.edu/someDepartment/home.index,然后把检索出来的对象进行封装,封装到) HTTP 响应报文中,并通过套接字向客户进行发送。
45-
- HTTP 服务器随即通知 TCP 断开 TCP 连接,实际上是需要等到客户接受完响应报文后才会断开 TCP 连接
46-
- HTTP 客户端接受完响应报文后,TCP 连接会关闭。HTTP 客户端从响应中提取出报文中是一个 HTML 响应文件,并检查该 HTML 文件,然后循环检查报文中其他内部对象。
47-
- 检查完成后,HTTP 客户端会把对应的资源通过显示器呈现给用户
42+
- DNS服务器会首先进行域名的映射,找到访问`www.someSchool.edu`所在的地址,然后HTTP客户端进程在80端口发起一个到服务器`www.someSchool.edu`的TCP连接(80端口是HTTP的默认端口)。在客户和服务器进程中都会有一个`套接字`与其相连。
43+
- HTTP客户端通过它的套接字向服务器发送一个HTTP请求报文。该报文中包含了路径`someDepartment/home.index`的资源,我们后面会详细讨论HTTP请求报文
44+
- HTTP服务器通过它的套接字接受该报文,进行请求的解析工作,并从其`存储器(RAM 或磁盘)`中检索出对象 [www.someSchool.edu/someDepartment/home.index,然后把检索出来的对象进行封装,封装到](http://www.someSchool.edu/someDepartment/home.index,然后把检索出来的对象进行封装,封装到)HTTP响应报文中,并通过套接字向客户进行发送。
45+
- HTTP服务器随即通知TCP断开TCP连接,实际上是需要等到客户接受完响应报文后才会断开TCP连接
46+
- HTTP客户端接受完响应报文后,TCP连接会关闭。HTTP客户端从响应中提取出报文中是一个HTML响应文件,并检查该HTML文件,然后循环检查报文中其他内部对象。
47+
- 检查完成后,HTTP客户端会把对应的资源通过显示器呈现给用户
4848

4949
至此,键入网址再按下回车的全过程就结束了。上述过程描述的是一种简单的`请求-响应`全过程,真实的请求-响应情况可能要比上面描述的过程复杂很多。
5050

@@ -190,4 +190,4 @@ HTTP + 加密 + 认证 + 完整性保护 = HTTPS
190190
- 邮箱 :charon.chui@gmail.com
191191
- Good Luck!
192192

193-
193+

JavaKnowledge/Java内存模型.md

+20-17
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
Java内存模型
22
===
33

4-
Java虚拟机(Java Virtual Machine)在执行Java程序的过程中,会把它管理的内存划分为五个不同的数据区域(Heap Memory、Stack Memory、Method Area、PC、Native Stack Memory),这些区域都有各自的用途、创建时间、销毁时间:
4+
Java虚拟机(Java Virtual Machine)在执行Java程序的过程中,会把它管理的内存划分为五个不同的数据区域(Heap Memory、
5+
Stack Memory、Method Area、PC、Native Stack Memory),这些区域都有各自的用途、创建时间、销毁时间:
56
![](https://raw.githubusercontent.com/CharonChui/Pictures/master/jvm_memory_model.jpeg)
67

78
## Program Counter Register
89

9-
程序计数器是一块较小的内存空间,严格来说是一个数据结构,用于保存当前正在执行的程序的内存地址,由于Java是支持多线程执行的,所以程序执行的轨迹不可能一直都是线性执行。当有多个线程交叉执行时,被中断的线程的程序当前执行到哪条内存地址必然要保存下来,以便用于被中断的线程恢复执行时再按照被中断时的指令地址继续执行下去。为了线程切换后能恢复到正确的执行位置,每个线程都需要有一个独立的程序计数器,各个线程之间计数器互不影响,独立存储,我们称这类内存区域为“线程私有”的内存,这在某种程度上有点类似于“ThreadLocal”,是线程安全的。可以看作是当前线程所执行的字节码的行号指示器。
10+
程序计数器是一块较小的内存空间,严格来说是一个数据结构,用于保存当前正在执行的程序的内存地址,由于Java是支持多线程执行的,所以程序执行的轨迹
11+
不可能一直都是线性执行。当有多个线程交叉执行时,被中断的线程的程序当前执行到哪条内存地址必然要保存下来,以便用于被中断的线程恢复执行时再按照
12+
被中断时的指令地址继续执行下去。为了线程切换后能恢复到正确的执行位置,每个线程都需要有一个独立的程序计数器,各个线程之间计数器互不影响,独立存储,
13+
我们称这类内存区域为“线程私有”的内存,这在某种程度上有点类似于“ThreadLocal”,是线程安全的。可以看作是当前线程所执行的字节码的行号指示器。
1014

1115
从上面的介绍中我们知道程序计数器主要有两个作用:
1216

@@ -22,20 +26,19 @@ Java虚拟机(Java Virtual Machine)在执行Java程序的过程中,会把它
2226
所有的对象实例和数组都存放到Heap内存中。Heap内存也称为共享内存。多线程可以共享这里面的数据。
2327

2428
- 堆内存在JVM启动的时候被加载(初始大小: -Xms)
25-
2629
- 堆内存在程序运行时会增加或减少
27-
2830
- 最小值: -Xmx
29-
30-
- 从结构上来分,可以分为新生代和老年代。而新生代又可以分为Eden空间、From Survivor空间(s0)、To Survivor空间(s1)。 所有新生成的对象首先都是放在新生代的。需要注意,Survivor的两个区是对称的,没先后关系,所以同一个区中可能同时存在从Eden复制过来的对象,和从前一个Survivor复制过来的对象,而复制到老年代的只有从第一个Survivor区过来的对象。而且,Survivor区总有一个是空的。
31+
- 从结构上来分,可以分为新生代和老年代。而新生代又可以分为Eden空间、From Survivor空间(s0)、To Survivor空间(s1)。 所有新生成的对象首先
32+
都是放在新生代的。需要注意,Survivor的两个区是对称的,没先后关系,所以同一个区中可能同时存在从Eden复制过来的对象,和从前一个Survivor复制
33+
过来的对象,而复制到老年代的只有从第一个Survivor区过来的对象。而且,Survivor区总有一个是空的。
3134

3235
![](https://raw.githubusercontent.com/CharonChui/Pictures/master/jvm_heap_memory.png)
3336

3437
在并发编程中,多个线程之间采取什么机制进行通信(信息交换),什么机制进行数据的同步?在Java语言中,采用的是共享内存模型来实现多线程之间的信息交换和数据同步的。
3538

3639
## Stack Memory
3740

38-
栈总是与线程关联在一起的,每当创建一个线程,JVM就会为该线程创建对应的线程栈,线程stack中包含有关线程调用了哪些方法以达到当前执行点的信息,也可以称之为调用栈,只要线程执行代码,调用栈就会发生改变。在这个栈中又会包含多个栈帧(Stack Frame),栈是由一个个栈帧组成,这些栈帧是与每个方法关联起来的,每运行一个方法就创建一个栈帧,每个栈帧会含有一些局部变量表、操作栈和方法返回值等信息。
41+
栈总是与线程关联在一起的,每当创建一个线程,JVM就会为该线程创建对应的线程栈,线程stack中包含有关线程调用了哪些方法以达到当前执行点的信息,也可以称之为调用栈,只要线程执行代码,调用栈就会发生改变。在这个栈中又会包含多个栈帧(Stack Frame),栈是由一个个栈帧组成,这些栈帧是与每个方法关联起来的,每运行一个方法就创建一个栈帧,每个栈帧会含有一些局部变量表、操作栈和方法返回值等信息。
3942

4043
局部变量表主要存放了编译器可知的各种数据类型(boolean、byte、char、short、int、float、long、double)、对象引用(reference类型,它不同于对象本身,可能是一个指向对象起始地址的引用指针,也可能是指向一个代表对象的句柄或其他与此对象相关的位置)。
4144

@@ -51,8 +54,8 @@ Java虚拟机(Java Virtual Machine)在执行Java程序的过程中,会把它
5154
![](https://raw.githubusercontent.com/CharonChui/Pictures/master/stack_heap.png)
5255

5356
- 局部变量可以是原始类型,在这种情况下,它完全保留在线程堆栈中。
54-
- 局部变量也可以是对对象的引用。在这种情况下,引用(局部变量)存储在线程堆栈中,但是对象本身(如果存储在堆中)
55-
- 一个对象可能包含方法,而这些方法可能包含局部变量。即使该方法所属的对象存储在堆内存中,这些局部变量也存储在线程堆内存中
57+
- 局部变量也可以是对对象的引用。在这种情况下,引用(局部变量)存储在线程堆栈中,但是对象本身(如果有)存储在堆中
58+
- 一个对象可能包含方法,而这些方法可能包含局部变量。即使该方法所属的对象存储在堆中,这些局部变量也存储在线程堆栈中
5659
- 对象的成员变量与对象本身一起存储在堆中。不管成员变量是原始类型时,以及它是对对象的引用时,都是如此。
5760
- 静态类变量也与类定义一起存储在堆中。
5861
- 引用对象的所有线程都可以访问堆上的对象。当线程可以访问对象时,它也可以访问该对象的成员变量。如果两个线程同时在同一个对象上调用一个方法,则它们都将有权访问该对象的成员变量,但是每个线程将拥有自己的局部变量副本。
@@ -92,7 +95,7 @@ Java 虚拟机栈会出现两种异常:StackOverFlowError 和 OutOfMemoryError
9295

9396
JVM会加载、链接、初始化class文件。一个class文件会把其所有所有符号引用都保留在一个位置,即常量池中。
9497

95-
每个class文件都会有一个对应constant pool。但是class文件中的常量池显示让不够的,因为需要再JVM上执行。这种情况下,需要runtime constant pool来服务JVM的运行。
98+
每个class文件都会有一个对应constant pool。但是class文件中的常量池显然是不够的,因为需要再JVM上执行。这种情况下,需要runtime constant pool来服务JVM的运行。
9699

97100
Java虚拟机加载的每个类或接口都有其常量池的内部版本,称为运行时常量池(runtime constant pool)。运行时常量池是特定于实现的数据结构,它与类文件中的常量池是一一对应映射的。因此,在最初加载类型之后,该类型的所有符号引用都驻留在该类型的运行时常量池中。包括字符串常量,类和接口名称,字段名称以及类中引用的其他常量。
98101

@@ -109,9 +112,9 @@ System.out.println(str1==str2);//false
109112
```java
110113
String str1 = "str";
111114
String str2 = "ing";
112-
115+
113116
String str3 = "str" + "ing";//常量池中的对象
114-
String str4 = str1 + str2; //在堆上创建的新的对象
117+
String str4 = str1 + str2; //在堆上创建的新的对象
115118
String str5 = "string";//常量池中的对象
116119
System.out.println(str3 == str4);//false
117120
System.out.println(str3 == str5);//true
@@ -178,7 +181,7 @@ JMM(Java Memory Model)规定了所有的变量都存储在主内存(Main Memor
178181

179182
由上述对JVM内存结构的描述中,我们知道了堆和方法区是线程共享的。而局部变量,方法定义参数和异常处理器参数就不会在线程之间共享,它们不会有内存可见性问题,也不受内存模型的影响。
180183

181-
Java线程之间的通信由Java内存模型(本文简称为JMM)控制,JMM决定一个线程对共享变量的写入何时对另一个线程可见。从抽象的角度来看,JMM定义了线程和主内存之间的抽象关系:线程之间的共享变量存储在主内存(main memory)中,每个线程都有一个私有的本地内存(local memory),本地内存中存储了该线程以读/写共享变量的副本。本地内存是JMM的一个抽象概念,并不真实存在。它涵盖了缓存,写缓冲区,寄存器以及其他的硬件和编译器优化。
184+
Java线程之间的通信由Java内存模型(JMM)控制,JMM决定一个线程对共享变量的写入何时对另一个线程可见。从抽象的角度来看,JMM定义了线程和主内存之间的抽象关系:线程之间的共享变量存储在主内存(main memory)中,每个线程都有一个私有的本地内存(local memory),本地内存中存储了该线程以读/写共享变量的副本。本地内存是JMM的一个抽象概念,并不真实存在。它涵盖了缓存,写缓冲区,寄存器以及其他的硬件和编译器优化。
182185

183186
假设线程A与线程B之间如要通信的话,必须要经历下面2个步骤:
184187

@@ -212,7 +215,7 @@ Class Reordering {
212215

213216

214217

215-
当然不行! 因为在writer方法中,可能发生了重排序,y的写入动作可能发在x写入之前,这种情况下,线程B就有可能看到x的值还是0。
218+
当然不行!因为在writer方法中,可能发生了重排序,y的写入动作可能发在x写入之前,这种情况下,线程B就有可能看到x的值还是0。
216219

217220
在Java内存模型中,描述了在多线程代码中,哪些行为是正确的、合法的,以及多线程之间如何进行通信,代码中变量的读写行为如何反应到内存、CPU缓存的底层细节。
218221

@@ -226,7 +229,7 @@ Class Reordering {
226229
a是在栈内存中的,当main()方法执行结束,a就被清理了。但是你创建的内部类中的方法却可能在main()方法执行完成后再去执行,但是这时候局部变量已经不存在了,那怎么解决这个问题呢?
227230
因此实际上是在访问它的副本,而不是访问原始的局部变量。
228231

229-
在Java的参数传递中,当基本类型作为参数传递时,传递的是值的拷贝,无论你怎么改变这个拷贝,原值是不会改变的;当对象作为参数传递时,传递的是对象的引用的拷贝,无论你怎么改变这个新的引用的指向,原来的引用是不会改变的(当然如果你通过这个引用改变了对象的内容,那么改变实实在在发生了)。知识点三,当final修饰基本类型变量时,不可更改其值,当final修饰引用变量时,不可更改其指向,只能更改其对象的内容。
232+
在Java的参数传递中,当基本类型作为参数传递时,传递的是值的拷贝,无论你怎么改变这个拷贝,原值是不会改变的;当对象作为参数传递时,传递的是对象的引用的拷贝,无论你怎么改变这个新的引用的指向,原来的引用是不会改变的(当然如果你通过这个引用改变了对象的内容,那么改变实实在在发生了)。而当final修饰基本类型变量时,不可更改其值,当final修饰引用变量时,不可更改其指向,只能更改其对象的内容。
230233

231234
在Java中内部类会持有外部类的引用和方法中参数的引用,当反编译class文件后,内部类的class文件的构造函数参数中会传入外部类的对象以及方法内局部变量,不管是基本数据类型还是引用变量,如果重新赋值了,会导致内外指向的对象不一致,所以java就暴力的规定使用final,不能重新赋值。
232235
所以用final修饰实际上就是为了变量值(数据)的一致性。 这里所说的数据一致性,对引用变量来说是引用地址的一致性,对基本类型来说就是值的一致性。
@@ -247,9 +250,9 @@ a是在栈内存中的,当main()方法执行结束,a就被清理了。但是
247250
- [Where Has the Java PermGen Gone?](https://www.infoq.com/articles/Java-PERMGEN-Removed/)
248251

249252

250-
253+
251254
---
252255
- 邮箱 :charon.chui@gmail.com
253256
- Good Luck!
254257

255-
258+

0 commit comments

Comments
 (0)