auto commit

This commit is contained in:
CyC2018 2019-04-24 11:48:37 +08:00
parent df717954ff
commit 7a049922d8
17 changed files with 18 additions and 20 deletions

View File

@ -389,7 +389,7 @@ transient Node<E> first;
transient Node<E> last;
```
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/c8563120-cb00-4dd6-9213-9d9b337a7f7c.png" width="450px"> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/c8563120-cb00-4dd6-9213-9d9b337a7f7c.png" width="500px"> </div><br>
### 2. 与 ArrayList 的比较
@ -411,7 +411,7 @@ transient Entry[] table;
Entry 存储着键值对。它包含了四个字段,从 next 字段我们可以看出 Entry 是一个链表。即数组中的每个位置被当成一个桶一个桶存放一个链表。HashMap 使用拉链法来解决冲突,同一个链表中存放哈希值相同的 Entry。
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/9420a703-1f9d-42ce-808e-bcb82b56483d.png" width="500px"> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/9420a703-1f9d-42ce-808e-bcb82b56483d.png" width="550px"> </div><br>
```java
static class Entry<K,V> implements Map.Entry<K,V> {
@ -487,7 +487,7 @@ map.put("K3", "V3");
- 计算键值对所在的桶;
- 在链表上顺序查找,时间复杂度显然和链表的长度成正比。
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/e0870f80-b79e-4542-ae39-7420d4b0d8fe.png" width="500px"> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/e0870f80-b79e-4542-ae39-7420d4b0d8fe.png" width="550px"> </div><br>
### 3. put 操作

View File

@ -61,7 +61,7 @@
# 一、线程状态转换
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/c80bbac0-72b3-4bd0-a63e-b9a11e88e1b6_200.png" width="800px"> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/adfb427d-3b21-40d7-a142-757f4ed73079.png" width="600px"> </div><br>
## 新建New
@ -736,7 +736,7 @@ java.util.concurrentJ.U.C大大提高了并发性能AQS 被认为是 J.
维护了一个计数器 cnt每次调用 countDown() 方法会让计数器的值减 1减到 0 的时候,那些因为调用 await() 方法而在等待的线程就会被唤醒。
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/29011257-8390-4792-b0bf-898be001d0bd_200.png" width="300px"> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/ba078291-791e-4378-b6d1-ece76c2f0b14.png" width="300px"> </div><br>
```java
public class CountdownLatchExample {
@ -785,7 +785,7 @@ public CyclicBarrier(int parties) {
}
```
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/ff8812b2-77e8-4bca-b427-4336e0e75af3_200.png" width="300px"> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/f71af66b-0d54-4399-a44b-f47b58321984.png" width="300px"> </div><br>
```java
public class CyclicBarrierExample {
@ -1022,7 +1022,7 @@ public class ForkJoinPool extends AbstractExecutorService
ForkJoinPool 实现了工作窃取算法来提高 CPU 的利用率。每个线程都维护了一个双端队列用来存储需要执行的任务。工作窃取算法允许空闲的线程从其它线程的双端队列中窃取一个任务来执行。窃取的任务必须是最晚的任务避免和队列所属线程发生竞争。例如下图中Thread2 从 Thread1 的队列中拿出最晚的 Task1 任务Thread1 会拿出 Task2 来执行,这样就避免发生竞争。但是如果队列中只有一个任务时还是会发生竞争。
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/e19452dd-220a-4a6b-bcb0-91ad5e5c4706.png" width="300px"> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/e42f188f-f4a9-4e6f-88fc-45f4682072fb.png" width="300px"> </div><br>
# 九、线程不安全示例
@ -1077,19 +1077,19 @@ Java 内存模型试图屏蔽各种硬件和操作系统的内存访问差异,
加入高速缓存带来了一个新的问题:缓存一致性。如果多个缓存共享同一块主内存区域,那么多个缓存的数据可能会不一致,需要一些协议来解决这个问题。
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/6b7f33c4-2dad-4f4b-aa54-d99c0dccc4c1_200.png" width="600px"> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/942ca0d2-9d5c-45a4-89cb-5fd89b61913f.png" width="600px"> </div><br>
所有的变量都存储在主内存中,每个线程还有自己的工作内存,工作内存存储在高速缓存或者寄存器中,保存了该线程使用的变量的主内存副本拷贝。
线程只能直接操作工作内存中的变量,不同线程之间的变量值传递需要通过主内存来完成。
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/c7399ff9-bdfe-48d8-94fe-eff5704b94eb_200.png" width="600px"> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/15851555-5abc-497d-ad34-efed10f43a6b.png" width="600px"> </div><br>
## 内存间交互操作
Java 内存模型定义了 8 个操作来完成主内存和工作内存的交互操作。
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/cb80b6f8-85bc-442c-979c-63f109311d1f_200.png" width="400px"> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/8b7ebbad-9604-4375-84e3-f412099d170c.png" width="450px"> </div><br>
- read把一个变量的值从主内存传输到工作内存中
- load在 read 之后执行,把 read 得到的值放入工作内存的变量副本中
@ -1112,11 +1112,11 @@ Java 内存模型保证了 read、load、use、assign、store、write、lock 和
下图演示了两个线程同时对 cnt 进行操作load、assign、store 这一系列操作整体上看不具备原子性,那么在 T1 修改 cnt 并且还没有将修改后的值写入主内存T2 依然可以读入旧值。可以看出,这两个线程虽然执行了两次自增运算,但是主内存中 cnt 的值最后为 1 而不是 2。因此对 int 类型读写操作满足原子性只是说明 load、assign、store 这些单个操作具备原子性。
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/e2d2d90f-95eb-4877-9d36-99d7b93695de_200.png" width="300px"> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/2797a609-68db-4d7b-8701-41ac9a34b14f.jpg" width="300px"> </div><br>
AtomicInteger 能保证多个线程修改的原子性。
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/2f1c9839-d582-4f75-863e-8f0a2ac63fb8_200.png" width="300px"> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/dd563037-fcaa-4bd8-83b6-b39d93a12c77.jpg" width="300px"> </div><br>
使用 AtomicInteger 重写之前线程不安全的代码之后得到以下线程安全实现:
@ -1224,7 +1224,7 @@ volatile 关键字通过添加内存屏障的方式来禁止指令重排,即
在一个线程内,在程序前面的操作先行发生于后面的操作。
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/e8454537-5a0c-49a2-8304-abae0b8887e1_200.png" width="180px"> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/874b3ff7-7c5c-4e7a-b8ab-a82a3e038d20.png" width="180px"> </div><br>
### 2. 管程锁定规则
@ -1232,7 +1232,7 @@ volatile 关键字通过添加内存屏障的方式来禁止指令重排,即
一个 unlock 操作先行发生于后面对同一个锁的 lock 操作。
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/e49b6fe9-5ad7-4fe9-975d-dceb10ffe5b4_200.png" width="350px"> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/8996a537-7c4a-4ec8-a3b7-7ef1798eae26.png" width="350px"> </div><br>
### 3. volatile 变量规则
@ -1240,7 +1240,7 @@ volatile 关键字通过添加内存屏障的方式来禁止指令重排,即
对一个 volatile 变量的写操作先行发生于后面对这个变量的读操作。
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/cc1acfb8-c507-4194-b16a-33388bd1cf82_200.png" width="400px"> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/942f33c9-8ad9-4987-836f-007de4c21de0.png" width="400px"> </div><br>
### 4. 线程启动规则
@ -1248,8 +1248,7 @@ volatile 关键字通过添加内存屏障的方式来禁止指令重排,即
Thread 对象的 start() 方法调用先行发生于此线程的每一个动作。
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/693426e6-b057-46a8-bfda-2cf681952756_200.png" width="380px"> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/6270c216-7ec0-4db7-94de-0003bce37cd2.png" width="380px"> </div><br>
### 5. 线程加入规则
@ -1257,8 +1256,7 @@ Thread 对象的 start() 方法调用先行发生于此线程的每一个动作
Thread 对象的结束先行发生于 join() 方法返回。
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/89a0024a-7485-4164-bc82-ebdea51f59e0_200.png" width="400px"> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/233f8d89-31d7-413f-9c02-042f19c46ba1.png" width="400px"> </div><br>
### 6. 线程中断规则
@ -1476,7 +1474,7 @@ public class ThreadLocalExample1 {
它所对应的底层结构图为:
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/4dc11e5e-c1d8-4391-be73-337cda32e155_200.png" width="500px"> </div><br>
<div align="center"> <img src="https://gitee.com/CyC2018/CS-Notes/raw/master/docs/pics/6782674c-1bfe-4879-af39-e9d722a95d39.png" width="500px"> </div><br>
每个 Thread 都有一个 ThreadLocal.ThreadLocalMap 对象。

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB