@@ -4523,7 +4523,7 @@ public class ArrayList<E> extends AbstractList<E>
45234523 }
45244524 ```
45254525
4526- * Fail-Fast:modCount 用来记录 ArrayList 结构发生变化的次数。 结构发生变化是指添加或者删除至少一个元素的所有操作,或者是调整内部数组的大小,仅仅只是设置元素的值不算结构发生变化
4526+ * Fail-Fast:modCount 用来记录 ArrayList 结构发生变化的次数, 结构发生变化是指添加或者删除至少一个元素的所有操作,或者是调整内部数组的大小,仅仅只是设置元素的值不算结构发生变化
45274527
45284528 在进行序列化或者迭代等操作时,需要比较操作前后 modCount 是否改变,如果改变了需要抛出 ConcurrentModificationException
45294529
@@ -4557,7 +4557,7 @@ public class ArrayList<E> extends AbstractList<E>
45574557
45584558###### LinkedList
45594559
4560- LinkedList是一个实现了List接口和Deque接口的双端链表 ,支持高效的插入和删除操作,另外它实现了Deque接口 ,使得LinkedList类也具有队列的特性
4560+ LinkedList是一个实现了List接口的**双端链表** ,支持高效的插入和删除操作,另外也实现了Deque接口 ,使得LinkedList类也具有队列的特性
45614561
45624562
45634563
@@ -4619,7 +4619,7 @@ LinkedList是一个实现了List接口和Deque接口的双端链表,支持高
46194619 * LinkedList不支持高效的随机元素访问,ArrayList支持
46204620 * 快速随机访问就是通过元素的序号快速获取元素对象(对应于`get(int index)`方法)。
462146215. 内存空间占用:
4622- * ArrayList的空 间浪费主要体现在在 list 列表的结尾会预留一定的容量空间
4622+ * ArrayList的空间浪费主要体现在在 list 列表的结尾会预留一定的容量空间
46234623 * LinkedList的空间花费则体现在它的每一个元素都需要消耗比 ArrayList更多的空间(因为要存放直接后继和直接前驱以及数据)
46244624
46254625
@@ -4989,8 +4989,8 @@ HashMap基于哈希表的Map接口实现,是以key-value存储形式存在,
49894989* JDK1.8 之前 HashMap 由 **数组+链表** 组成
49904990
49914991 * 数组是 HashMap 的主体
4992- * 链表则是为了解决哈希冲突而存在的(“ 拉链法” 解决冲突)
4993- ** 两个对象调用的hashCode方法计算的哈希码值(键的哈希)一致导致计算的数组索引值相同**
4992+ * 链表则是为了解决哈希冲突而存在的(** 拉链法** 解决冲突),拉链法就是头插法
4993+ 两个对象调用的hashCode方法计算的哈希码值(键的哈希)一致导致计算的数组索引值相同
49944994
49954995* JDK1.8 以后 HashMap 由 **数组+链表 +红黑树**数据结构组成
49964996
@@ -5225,9 +5225,9 @@ HashMap继承关系如下图所示:
52255225 static final int TREEIFY_THRESHOLD = 8;
52265226 ```
52275227
5228- * 为什么Map桶中节点个数大于8才转为红黑树?
5228+ 为什么Map桶中节点个数大于8才转为红黑树?
52295229
5230- 在HashMap中有一段注释说明:**空间和时间的权衡**
5230+ * 在HashMap中有一段注释说明:**空间和时间的权衡**
52315231
52325232 ```java
52335233 TreeNodes占用空间大约是普通节点的两倍,所以我们只在箱子包含足够的节点时才使用树节点。当节点变少(由于删除或调整大小)时,就会被转换回普通的桶。在使用分布良好的用户hashcode时,很少使用树箱。理想情况下,在随机哈希码下,箱子中节点的频率服从"泊松分布",默认调整阈值为0.75,平均参数约为0.5,尽管由于调整粒度的差异很大。忽略方差,列表大小k的预期出现次数是(exp(-0.5)*pow(0.5, k)/factorial(k))
@@ -5490,18 +5490,26 @@ transient int size;
54905490
549154914. resize
54925492
5493- 当HashMap中的元素个数超过(数组长度)*loadFactor(负载因子)`时,就会进行数组扩容。扩容会伴随着一次重新hash分配,并且会遍历hash表中所有的元素,非常耗时,所以要尽量避免resize
5493+ 当HashMap中的元素个数超过` (数组长度)*loadFactor(负载因子)`时,就会进行数组扩容。扩容会伴随着一次重新hash分配,并且会遍历hash表中所有的元素,非常耗时,所以要尽量避免resize
54945494
5495- HashMap在进行扩容时,使用的rehash方式非常巧妙,因为每次扩容都是翻倍,与原来计算的 (n-1)&hash的结果相比,只是多了一个bit位,节点**要么就在原来的位置,要么就被分配到"原位置+旧容量"的位置**
5495+ 扩容机制为扩容为原来容量的2倍:
54965496
5497- 判断:e.hash与oldCap对应的有效高位上的值是1,即当前数组长度n为1的位为 x,如果key的哈希值 x 位也为1,则扩容后的索引为 now + n
5497+ ```java
5498+ else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
5499+ oldCap >= DEFAULT_INITIAL_CAPACITY)
5500+ newThr = oldThr << 1; // double threshold
5501+ ```
54985502
5499- 注意:这里也要求**数组长度2的幂 **
5503+ HashMap在进行扩容后,节点**要么就在原来的位置,要么就被分配到"原位置+旧容量"的位置 **
55005504
5505+ 判断:e.hash与oldCap对应的有效高位上的值是1,即当前数组长度n为1的位为 x,如果key的哈希值 x 位也为1,则扩容后的索引为 now + n
5506+
5507+ 注意:这里也要求**数组长度2的幂**
5508+
55015509 
5502-
5510+
55035511 红黑树节点:扩容时split方法会将树**拆成高位和低位两个链表**,判断长度是否小于等于6
5504-
5512+
55055513 ```java
55065514 //如果低位链表首节点不为null,说明有这个链表存在
55075515 if (loHead != null) {
@@ -14814,38 +14822,63 @@ JDK 自带了**监控工具,位于 JDK 的 bin 目录下**,其中最常用
1481414822
1481514823# JUC
1481614824
14817- ## 概述
14825+ ## 进程
14826+
14827+ ### 概述
1481814828
1481914829进程:程序是静止的,进程实体的运行过程就是进程,是系统进行资源分配的基本单位
1482014830
1482114831进程的特征:动态性、并发性、独立性、异步性、结构性
1482214832
14823- **并行**:在同一时刻,有多个指令在多个CPU上同时执行
14824- **并发**:在同一时刻,有多个指令在单个CPU上交替执行
14825-
1482614833**线程**:线程是属于进程的,是一个基本的CPU执行单元,是程序执行流的最小单元。线程是进程中的一个实体,是被系统独立调度和分配的基本单位,线程本身不拥有系统资源,只拥有一点在运行中必不可少的资源,但它可与同属一个进程的其他线程共享进程所拥有的全部资源。
1482714834
1482814835关系:一个进程可以包含多个线程,这就是多线程,比如看视频是进程,图画、声音、广告等就是多个线程
1482914836
1483014837线程的作用:使多道程序更好的并发执行,提高资源利用率和系统吞吐量,增强操作系统的并发性能
1483114838
14839+ **并发并行**:
14840+
14841+ * 并行:在同一时刻,有多个指令在多个CPU上同时执行
14842+ * 并发:在同一时刻,有多个指令在单个CPU上交替执行
14843+
14844+ **同步异步**:
14845+
14846+ * 需要等待结果返回,才能继续运行就是同步
14847+ * 不需要等待结果返回,就能继续运行就是异步
14848+
14849+
14850+
14851+
14852+
14853+ ### 对比
14854+
1483214855线程进程对比:
1483314856
1483414857* 进程基本上相互独立的,而线程存在于进程内,是进程的一个子集
14858+
1483514859* 进程拥有共享的资源,如内存空间等,供其内部的线程共享
14860+
1483614861* 进程间通信较为复杂
14837- * 同一台计算机的进程通信称为 IPC(Inter-process communication)
14838- * 不同计算机之间的进程通信,需要通过网络,并遵守共同的协议,例如 HTTP
1483914862
14840- * 线程通信相对简单,因为它们共享进程内的内存,一个例子是多个线程可以访问同一个共享变量
14841- * 线程更轻量,线程上下文切换成本一般上要比进程上下文切换低
14863+ 同一台计算机的进程通信称为 IPC(Inter-process communication)
1484214864
14843- 同步异步:
14865+ * 信号量:信号量是一个计数器,用于多进程对共享数据的访问,解决同步相关的问题并避免竞争条件
14866+ * 共享存储:多个进程可以访问同一块内存空间,需要使用信号量用来同步对共享存储的访问
14867+ * 管道通信:管道是用于连接一个读进程和一个写进程以实现它们之间通信的一个共享文件,pipe文件
14868+ * 匿名管道(Pipes) :用于具有亲缘关系的父子进程间或者兄弟进程之间的通信,只支持半双工通信
14869+ * 命名管道(Names Pipes):以磁盘文件的方式存在,可以实现本机任意两个进程通信,遵循FIFO
14870+ * 消息队列:消息的链表,具有特定的格式,存放在内存中并由消息队列标识符标识,对比管道:
14871+ * 匿名管道存在于内存中的文件;命名管道存在于实际的磁盘介质或者文件系统;消息队列存放在内核中,只有在内核重启(操作系统重启)或者显示地删除一个消息队列时,该消息队列才被真正删除
14872+ * 读进程可以根据消息类型有选择地接收消息,而不像 FIFO 那样只能默认地接收
1484414873
14845- * 需要等待结果返回,才能继续运行就是同步
14846- * 不需要等待结果返回,就能继续运行就是异步
14874+ 不同计算机之间的进程通信,需要通过网络,并遵守共同的协议,例如 HTTP
1484714875
14848- 萨克尽快撒娇看啊是卡接口
14876+ * 套接字:与其它通信机制不同的是,它可用于不同机器间的进程通信
14877+
14878+ * 线程通信相对简单,因为它们共享进程内的内存,一个例子是多个线程可以访问同一个共享变量
14879+ Java中的通信机制:volatile、等待/通知机制、join方式、threadLocal
14880+
14881+ * 线程更轻量,线程上下文切换成本一般上要比进程上下文切换低
1484914882
1485014883
1485114884
@@ -18140,8 +18173,6 @@ Cell 是数组形式,**在内存中是连续存储的**,一个 Cell 为 24
1814018173
1814118174
1814218175
18143-
18144-
1814518176***
1814618177
1814718178
0 commit comments