Skip to content

Commit 545bc37

Browse files
committed
add
1 parent 80ba1a7 commit 545bc37

File tree

16 files changed

+557
-110
lines changed

16 files changed

+557
-110
lines changed

java/0-JavaSE/c-集合类/2-Map集合.md

+3-51
Original file line numberDiff line numberDiff line change
@@ -333,57 +333,9 @@ key: Person{id=1002, name='李四', age=20} value: 2020-02
333333
334334
![](https://iqqcode-blog.oss-cn-beijing.aliyuncs.com/img/20200525112147.png)
335335

336-
## 6. Map集合的遍历
336+
<br>
337337

338-
**【方式一】通过map.keySet()获取key,通过key找到value**
339-
340-
![](https://iqqcode-blog.oss-cn-beijing.aliyuncs.com/img/20200525110552.png)
341-
342-
**【方式二】通过Map.Entry(String,String)获取,然后使用entry.getKey()获取到键,通过entry.getValue()获取到值**
343-
344-
![](https://iqqcode-blog.oss-cn-beijing.aliyuncs.com/img/20200525111456.png)
345-
346-
**【方式三】先放入Set集合中,Iterator遍历获取**
347-
348-
![](https://iqqcode-blog.oss-cn-beijing.aliyuncs.com/img/20200525111943.png)
349-
350-
**【方式四】只遍历键或者值,通过加强for循环**
351-
352-
![](https://iqqcode-blog.oss-cn-beijing.aliyuncs.com/img/20200525112035.png)
353-
354-
----------------------------------------------------------------------------------
355-
356-
**计算一个字符串中每个字符出现次数**
357-
358-
解题思路:
359-
360-
1. 使用 Scanner获取用户输入的字符串
361-
362-
2. 创建Map集合,key是字符串中的字符, value是字符的个数
363-
364-
3. 遍历字符串获取每一个字符
365-
366-
4. 使用获取到的字符,去Map集合判断key是否存在
367-
368-
- key存在:
369-
370-
- 通过字符(key),获取vaue(字符个数)
371-
372-
- value++
373-
374-
- put(key, value)把新的 value存储到Map集合中
375-
376-
- key不存在:
377-
378-
- put(key, 1)
379-
380-
5. 遍历Map集合,输出结果
381-
382-
![](https://iqqcode-blog.oss-cn-beijing.aliyuncs.com/img/20200525114532.png)
383-
384-
385-
386-
## 7. 表格数据存储
338+
## 6. 表格数据存储
387339

388340
> 使用容器来存储表格数据
389341
@@ -488,7 +440,7 @@ Student{id=1002, name='李四', age=20, graduation=2021-07}
488440
Student{id=1003, name='王五', age=22, graduation=2017-07}
489441
```
490442

491-
## 8. 是否可以存储null
443+
## 7. 是否可以存储null
492444

493445
| 结构 | null |
494446
| :-------: | :--: |

java/0-JavaSE/c-集合类/3-HashMap.md

+20-1
Original file line numberDiff line numberDiff line change
@@ -380,10 +380,12 @@ loadFactor = size / capacity
380380
- 0.75为加载因子
381381
- 创建新数组,2倍扩容,浅拷贝原数组
382382

383-
HashMap在进行扩容时,**不需要重新计算hash值**`rehash`方式非常巧妙,因为每次扩容都是翻倍,与原来计算的`(n-1)&hash`的结果相比,只是多了一个bit位,所以节点要么就在**原来**的位置,要么就被分配到**原位置+旧容量**这个位置
383+
HashMap在进行扩容时,**不需要重新计算hash值**`rehash`方式非常巧妙,因为每次扩容都是翻倍,与原来计算的`(n-1)&hash`结果相比,只是多了一个bit位,所以节点要么就在**原来**的位置,要么就被分配到**原位置+旧容量**这个位置
384384

385385
![](3-HashMap.assets/20200812101302.png)
386386

387+
<img src="3-HashMap.assets/image-20200829163933608.png" alt="image-20200829163933608" style="zoom:67%;" />
388+
387389
**<font color = red>【注意】:</font>**
388390

389391
- 扩容并不是直接将数组对应`hash`下的链表直接复制,而是节点逐个移动,*重新计算Hash值*
@@ -400,6 +402,15 @@ HashMap在进行扩容时,**不需要重新计算hash值**。`rehash`方式非
400402

401403
- JDK7扩容采用头插法,导致数据-移动到扩容后的数组顺序发生变化
402404

405+
<br>
406+
407+
## 5. 删除remove
408+
409+
- 若为树,查找为`O(logn)`
410+
- 若为链表,查找为`O(n)`
411+
412+
<br>
413+
403414
## 6. 并发问题
404415

405416
### 问题复现
@@ -496,3 +507,11 @@ public static void main(String[] args) {
496507
}
497508
```
498509

510+
511+
512+
## 7. JDK7多线程下扩容产生循环链表
513+
514+
> https://www.bilibili.com/video/BV1x741117jq?p=2
515+
>
516+
> - 37:40开始
517+

java/0-JavaSE/d-多线程/JUC/4.Java内存模型JMM详解.md

+37-7
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ MESI缓存一致性协议,通过对总线的侦听机制,很好地解决了
280280

281281
> 由于汇编代码比较长,虽然俺学了微机原理,但真的是看不懂😭。就挑最重要的一句摘录出来解释
282282
283-
    
283+
   
284284

285285
```java
286286
0x0000000002c860bf:lock add dword ptr [rsp], Oh ; *putstatic initFlag
@@ -544,19 +544,49 @@ CPU为了提高执行效率,这三步操作的顺序可以是123,也可以
544544

545545
- sfence:即写屏障(Store Barrier),在写指令之后插入写屏障,能让写入缓存的最新数据写回到主内存,以保证写入的数据立刻对其他线程可见。
546546

547-
- mfence,即全能屏障,具备ifence和sfence的能力。
547+
548548

549549
- [ ] Lock前缀:Lock不是一种内存屏障,但是它能完成类似全能型内存屏障的功能。
550550

551551
`volatile`会给代码添加一个内存屏障,指令重排序的时候不会把后面的指令重排序到屏障的位置之前
552552

553553
![](https://iqqcode-blog.oss-cn-beijing.aliyuncs.com/img/20200613084031.png)
554554

555-
> PS😐:只有一个CPU的时候,这种内存屏障是多余的。只有多个CPUI访问同一块内存的时候,就需要内存屏障了。
555+
> PS😐:只有一个CPU的时候,这种内存屏障是多余的。只有多个CPU访问同一块内存的时候,就需要内存屏障了
556+
557+
558+
559+
### 读写屏障
560+
561+
**写屏障**:保证 `屏障之前`的代码**不会**进行重排序
562+
563+
**读屏障**:保证 `屏障之后`的代码**不会**进行重排序
564+
565+
```java
566+
static volatile boolean read;
567+
568+
public void actor1() {
569+
num = 2;
570+
ready = true; // 写屏障
571+
}
572+
573+
public void actor2() {
574+
// 读屏障
575+
if(ready) {
576+
res = num + num;
577+
} else {
578+
res = 1;
579+
}
580+
}
581+
```
582+
583+
通过读写屏障来保证内存之间的有序性,禁止指临重排。
584+
585+
<br>
556586

557587
### JMM的Happens-Before原则
558588

559-
Happens-Before 是java内存模型中的语义规范,来阐述操作之间内存的可见性,可以确保一条语句的所有“写内存”操作对另一条语句是可见的。
589+
Happens-Before 是java内存模型中的语义规范,**保证内存操作之间的可见性**,可以确保一条语句的所有“写内存”操作对另一条语句是可见的。
560590

561591
**Happens-Before原则如下:**
562592

@@ -568,13 +598,13 @@ Happens-Before 是java内存模型中的语义规范,来阐述操作之间内
568598

569599
4. 传递规则:如果操作A先行发生于操作B,而操作B又先行发生于操作C,则可以得出操作A先行发生于操作C;
570600

571-
5. 线程启动规则:Thread对象的start()方法先行发生于此线程的每个一个动作;
601+
5. 线程启动规则:Thread对象的`start()`方法先行发生于此线程的每个一个动作;
572602

573-
6. 线程中断规则:对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生;
603+
6. 线程中断规则:对线程`interrupt()`方法的调用先行发生于被中断线程的代码检测到中断事件的发生;
574604

575605
7. 线程终结规则:线程中所有的操作都先行发生于线程的终止检测,我们可以通过Thread.join()方法结束、Thread.isAlive()的返回值手段检测到线程已经终止执行;
576606

577-
8. 对象终结规则:一个对象的初始化完成先行发生于他的finalize()方法的开始;
607+
8. 对象终结规则:一个对象的初始化完成先行发生于他的`finalize()`方法的开始;
578608

579609
以上的happens-before原则为volatile关键字的可见性提供了强制保证。
580610

java/0-JavaSE/d-多线程/Thread/5.synchnized原理及优化.md

+10-19
Original file line numberDiff line numberDiff line change
@@ -162,31 +162,22 @@ synchronized的操作都是互斥的,Monitor机制是由操作系统来提供
162162

163163
**优化的思想:让每个线程通过同步代码块时的速度提高**
164164

165-
----
165+
### 锁升级的过程
166166

167-
### CAS自旋
167+
面:前面你提到synchronized是个重量级锁,那它的优化有了解嘛?
168168

169-
CAS自旋,无锁实现的同步----乐观锁Compare And Swap
169+
应:为了减少获得锁和和释放锁带来的性能损耗引入了偏向锁、轻量级锁、重量级锁来进行优化,锁升级的过程如下:
170170

171-
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200530181502532.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzIzMjk1NQ==,size_16,color_FFFFFF,t_70)
172-
`Compare And Swap(O, V, N)`
171+
首先是一个**无锁**的状态,当线程进入同步代码块的时候,会检查对象头内和栈帧中的锁记录里是否存入存入当前线程的ID,如果没有使用**CAS **进行替换。以后该线程进入和退出同步代码块不需要进行CAS 操作来加锁和解锁,只需要判断对象头的Mark word内是否存储指向当前线程的偏向锁。如果有表示已经获得锁,如果没有或者不是,则需要使用CAS进行替换,如果设置成功则当前线程持有偏 向锁,反之将偏向锁进行撤销并升级为轻量级锁。
172+
  
173+
轻量级锁加锁过程,线程在执行同步块之前,JVM会在当前线程的栈帧中创建用于存储锁记录的空间,并将对象头的Mark Word复制到锁记录(Displaced Mark Word)中,然后线程尝试使用CAS 将对象头中的Mark Word替换为指向锁记录的指针。如果成功,当前线程获得锁,反之表示其他线程竞争锁,当前线程便尝试使用自旋来获得锁。
174+
  
175+
轻量级锁解锁过程,解锁时,会使用CAS将Displaced Mark Word替换回到对象头,如果成功,则表示竞争没有发生,反之则表示当前锁存在竞争锁就会膨胀成重量级锁。
173176

174-
**自旋带来的问题: ABA问题**
177+
**升级过程流程图**
178+
![在这里插入图片描述](5.synchnized原理及优化.assets/20200901222222643.png)
175179

176-
- 解决方法: 添加版本号 A.1----> B.2
177180

178-
自旋在CPU上跑无用指令,虽然减少了操作系统的开销,但是浪费了CPU资源
179-
180-
**JVM自适应自旋 :** 根据以往自旋等待时能否获取锁,来动态调整自旋的时间(循环数)
181-
182-
- JVM尝试自旋一段时间,若在此时间内线程成功获取到锁,在下次获取锁时,适当延长自旋时间;
183-
- 若在此时间内线程没有获取到锁,在下次获取锁时,适当缩短自旋时间
184-
185-
**公平性问题**
186-
187-
- 处于阻塞状态的线程可能一直无法获取到锁,自旋状态的线程更容易获取到锁
188-
189-
- Lock锁可以实现公平性,synchronized是非公平锁
190181

191182
----------
192183

java/0-JavaSE/d-多线程/Thread/7.死锁.md

+9-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
## 1. 死锁
22

3-
死锁的产生:细粒度的多把锁🔒下,要同时获取多个锁资源可能会产生
3+
死锁的产生:细粒度的多把锁🔒下,要同时获取对方的锁资源
44

55
有这样的情况:一个线程需要同时获取多把锁,这时就容易发生死锁
66

@@ -95,7 +95,7 @@ public class DeadLock {
9595

9696
**2. jstack查看当前线程信息**
9797

98-
![image-20200823135835637](7.死锁及Lock锁体系.assets/image-20200823135835637.png)
98+
![image-20200823135835637](7.死锁及Lock锁体系.assets/image-20200823135835637.png)
9999

100100
【日志显示】
101101

@@ -173,7 +173,13 @@ Found 1 deadlock.
173173

174174
**破坏死锁占有且等待的条件,让两个线程不再同时拿到对方想要的锁**
175175

176-
在Lock接口出现之前,java程序主要是靠`synchronized`关键字实现锁功能。而JDK5之后,并发包中增加了Lock接口,它提供了与synchronized一样的锁功能。虽然它失去了像synchronize隐式加锁解锁的便捷性(Lock锁为显式),但是却拥有了获取锁和释放锁的可操作性,可中断的获取锁以及超时获取锁等多种synchronized关键字所不具备的同步特性(synchronized锁是互斥的)
176+
Lock解决死锁,**破坏不可抢占**
177+
178+
1. 响应中断`lockInterruptibly`
179+
2. 支持超时`boolean tryLock(long time, TimeUnit unit)`
180+
3. 非阻塞式获取锁,线程若获取不到锁,线程直接退出`boolean tryLock()`
181+
182+
在Lock接口出现之前,Java程序主要是靠`synchronized`关键字实现锁功能。而JDK5之后,并发包中增加了Lock接口,它提供了与synchronized一样的锁功能。虽然它失去了像synchronize隐式加锁解锁的便捷性(Lock锁为显式),但是却拥有了获取锁和释放锁的可操作性,可中断的获取锁以及超时获取锁等多种synchronized关键字所不具备的同步特性(synchronized锁是互斥的)
177183

178184
<br>
179185

java/0-JavaSE/d-多线程/Thread/9.线程池.md

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
> 线程池:4大方法、7大参数、4种拒绝策略
1+
> 线程池:4大方法、7大参数、4种拒绝策略
22
33
## 1. 线程池
44

@@ -14,7 +14,7 @@
1414

1515
### 线程池概述
1616

17-
程序启动一个新的线程的成本是比较高的,因为它要与操作系统来交互。而使用线程池可以很好的提高性能,尤其是当程序中要创建大量<font color=green>生命周期很短的线程时</font>,更应该考虑使用**线程池**
17+
程序启动一个新的线程的成本是比较高的,因为它要与操作系统来交互。而使用线程池可以很好的提高性能,尤其是当程序中要创建大量<font color=green>**生命周期很短的线程时**</font>,更应该考虑使用**线程池**
1818

1919
**线程池里的每一个线程在调用结束后,并不会死亡,而是再次回到线程池中成为空闲状态,再次等待调度**
2020

@@ -93,13 +93,13 @@ public ThreadPoolExecutor(int corePoolSize,
9393

9494
2. int maximumPoolSize:最大核心池大小
9595

96-
3. long keepAliveTime:超时不调用就会释放
96+
3. long keepAliveTime:生存时间,超时不调用就会释放(针对救急线程)
9797

98-
4. TimeUnit unit:超时单位
98+
4. TimeUnit unit:超时单位(针对救急线程)
9999

100100
5. BlockingQueue<Runnable> workQueue:阻塞队列
101101

102-
6. ThreadFactory threadFactory:线程工厂,创建线程
102+
6. ThreadFactory threadFactory:线程工厂,创建线程并为线程命名
103103

104104
7. RejectedExecutionHandler handler:拒绝策略
105105

@@ -275,7 +275,7 @@ public class Test {
275275

276276
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200530003622555.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzIzMjk1NQ==,size_16,color_FFFFFF,t_70)
277277

278-
![\[外链图片转存失败(img-4QrjGqJw-1565343912034)(C:\Users\j2726\AppData\Roaming\Typora\typora-user-images\1564904750301.png)\]](https://img-blog.csdnimg.cn/20190809192817740.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzIzMjk1NQ==,size_16,color_FFFFFF,t_70)
278+
![](https://img-blog.csdnimg.cn/20190809192817740.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzIzMjk1NQ==,size_16,color_FFFFFF,t_70)
279279

280280
当一个任务提交给线程池时
281281

java/0-JavaSE/g-JVM/a-类加载系统/类加载系统.md

+21-4
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
**Java程序,由编译到运行期间的过程是怎样的?**(概念简述)
66

7-
- 首先,通过编译器将`.java`程序编译成`.class`文件
7+
- 首先,通过编译器将`.jav a`程序编译成`.class`文件
88

99
- 然后通过**Class Loader**类加载器加载到内存中,生成`Class`对象
1010

@@ -88,7 +88,11 @@
8888

8989
此方法不需定义,是 javac编译器自动收集类中的所有类变量的赋值动作和静态代码块中的语句合并而来
9090

91-
-------------------
91+
<br>
92+
93+
**类加载时,JVM确保了类加载的过程是线程安全的。只有当前类加载完成,其他类才会被加载**
94+
95+
<hr>
9296

9397
## 3. 类加器的分类
9498

@@ -238,10 +242,23 @@ public class String {
238242

239243
**【双亲委派模型优势】**
240244

241-
- <font color="pink">避免类的重复加载</font>
242-
245+
- <font color="pink">隔离加载类,避免类的重复加载</font>
243246
- <font color="pink">保护程序安全、防止核心API被篡改</font>
244247

248+
<br>
249+
250+
### Tomcat的类加载机制
251+
252+
<img src="类加载系统.assets/image-20200905003423993.png" alt="image-20200905003423993" style="zoom:40%;" />
253+
254+
每一个部署在Tomcat服务器上的应用的类加载器是WebappClassLoader,有多少个应用,就有多少个这样独立的加载器。
255+
256+
**Tomcat默认的类加载机制并不是双亲委派模型**(可以改)。
257+
258+
Tomcat破坏双亲委派模型,是为了**将各个Web应用隔离开**
259+
260+
> 例如JDK7和JDK8下,同一个jar包属于不同的版本,我们需要隔离加载不同的版本。
261+
245262
## 5. Class对象是否相等
246263

247264
怎么样判断类加载器加载到内存中的两个Class对象是否相等?

java/0-JavaSE/g-JVM/b-运行时数据区/04.虚拟机栈.md

+5-5
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
【基于栈的优势】:跨平台,指令集小,编译器容易实现;
1010

11-
【劣势】:性能下降,实现的同样的功能指令多
11+
【劣势】:相比基于寄存器的方式,性能下降,实现的同样的功能指令多
1212

1313
### 内存中的栈与堆
1414

@@ -42,9 +42,9 @@ Java虚拟机规范允许<font color = red>Java栈的大小是动态的或者固
4242

4343
- 如果线程请求的栈的深度大于虚拟机所允许的最大深度,抛出`StackOverflowError`
4444

45-
- 如果Java虚拟机栈可以动态扩展,并且在尝试扩展的时候无法中请到足够的内存,或者在创建新的线程时没有足够的内存去创建对应的虚拟机栈,那JVM将会抛出`OutOfMemoryError`异常
45+
- 如果Java虚拟机栈可以动态扩展,并且在尝试扩展的时候无法中请到足够的内存,或者在**创建新的线程时**没有足够的内存去创建对应的虚拟机栈,那JVM将会抛出`OutOfMemoryError`异常
4646

47-
> HotSpot虚拟机栈容量不可以动态扩展,但是申请失败是仍会产生OOM
47+
> HotSpot虚拟机栈容量不可以动态扩展,但是申请失败(并未拓展)仍会产生OOM,就是在创建新的线程时,已经没有足够内存为其分配空间来创建。
4848
4949
【手动设置虚拟机栈的容量大小】
5050

@@ -96,7 +96,7 @@ Java虚拟机规范允许<font color = red>Java栈的大小是动态的或者固
9696

9797
局部变量表Local Variables(局部变量数组或者本地变量表)。
9898

99-
1. 局部变量表是一个<font color = pink>数字数组</font>,主要用于存储方法参数和定义在方法体内的局部变量
99+
1. 局部变量表是一个<font color = pink>数字数组</font>,主要用于存储方法参数 和 定义在方法体内的局部变量
100100

101101
- 数据类型包括:基本数据类型、引用类型、返回值类型
102102

@@ -201,7 +201,7 @@ public class LocalVariablesTest01 {
201201

202202
> 局部变量表和操作数栈底层都是采用数组实现的,所以一旦初始化后,长度是固定不变的
203203
204-
这些数据类型在局部变量表中的存储空间用局部**变量槽(Slot)**来表示,`long``double`是64位占两个槽,其余占一个。
204+
这些数据类型在局部变量表中的存储空间用局部 **变量槽(Slot)**来表示,`long``double`是64位占两个槽,其余占一个。
205205

206206
> 所以局部变量表的容量就是槽的个数,在编译期间就是确定的
207207
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
![timg](Spring核心思想.assets/timg.jpeg)
1+
![timg](Spring核心思想.assets/timg.jpeg)

0 commit comments

Comments
 (0)