Skip to content

Commit fcae887

Browse files
committed
更新Java基础知识总结
1 parent 816ea84 commit fcae887

File tree

1 file changed

+21
-40
lines changed

1 file changed

+21
-40
lines changed

Java/Java基础.md

Lines changed: 21 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1202,6 +1202,9 @@ Selector:使用更少的线程来就可以来处理通道了,相比使用多
12021202

12031203
# ThreadLocal
12041204
线程本地变量。当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程。
1205+
1206+
## 原理
1207+
12051208
每个线程都有一个ThreadLocalMap(ThreadLocal内部类),Map中元素的键为ThreadLocal,而值对应线程的变量副本。
12061209

12071210
![image-20200715234257808](../img/threadlocal.png)
@@ -1277,7 +1280,7 @@ public class ThreadLocalDemo {
12771280
```
12781281
ThreadLocal 并不是用来解决共享资源的多线程访问的问题,因为每个线程中的资源只是副本,并不共享。因此ThreadLocal适合作为线程上下文变量,简化线程内传参。
12791282

1280-
### 内存泄漏
1283+
## 内存泄漏
12811284

12821285
每个Thread都有⼀个ThreadLocalMap的内部属性,map的key是ThreaLocal,定义为弱引用,value是强引用类型。GC的时候会⾃动回收key,而value的回收取决于Thread对象的生命周期。一般会通过线程池的方式复用Thread对象节省资源,这也就导致了Thread对象的生命周期比较长,这样便一直存在一条强引用链的关系:Thread --> ThreadLocalMap-->Entry-->Value,随着任务的执行,value就有可能越来越多且无法释放,最终导致内存泄漏。
12831286

@@ -1292,15 +1295,15 @@ Log log = new Log("INFO",System.currentTimeMillis() - currentTime.get());
12921295
currentTime.remove();
12931296
```
12941297

1295-
### 使用场景
1298+
## 使用场景
12961299

12971300
ThreadLocal 适用场景:每个线程需要有自己单独的实例,且需要在多个方法中共享实例,即同时满足实例在线程间的隔离与方法间的共享。比如Java web应用中,每个线程有自己单独的 Session 实例,就可以使用ThreadLocal来实现。
12981301

12991302

13001303

1301-
## 线程安全类
1304+
# 线程安全类
13021305

1303-
线程安全:代码段在多线程下执行和在单线程下执行能获得一样的结果
1306+
线程安全:代码段在多线程下执行和在单线程下执行能获得一样的结果
13041307
线程安全类:线程安全的类其方法是同步的,每次只能有一个线程访问,效率较低。
13051308
- vector:比arraylist多了个同步化机制,效率较低
13061309
- stack:堆栈类,继承自vector
@@ -1316,9 +1319,9 @@ Iterator和Enumeration的重要区别:
13161319

13171320

13181321

1319-
## 常见操作
1322+
# 常见操作
13201323

1321-
### 排序
1324+
## 排序
13221325

13231326
数组
13241327

@@ -1328,7 +1331,7 @@ Arrays.sort(jdArray, (int[] jd1, int[] jd2) -> {return jd1[0] - jd2[0];});
13281331

13291332

13301333

1331-
### 数组操作
1334+
## 数组操作
13321335

13331336
数组遍历
13341337

@@ -1371,9 +1374,9 @@ List<String> list = new ArrayList<String>(Arrays.asList(array));
13711374

13721375

13731376

1374-
### 拷贝
1377+
## 拷贝
13751378

1376-
#### 数组拷贝
1379+
### 数组拷贝
13771380

13781381
```java
13791382
System.arraycopy(Object src, int srcPos, Object dest, int desPos, int length)
@@ -1391,7 +1394,7 @@ for(int i = 0; i < arr.length; i++) {
13911394
}
13921395
```
13931396

1394-
#### 对象拷贝
1397+
### 对象拷贝
13951398

13961399
实现对象克隆有两种方式:
13971400

@@ -1436,26 +1439,26 @@ System.out.println(dog2); // Dog{id='1', name='Dog1 changed'}
14361439

14371440
如果一个类引用了其他类,引用的类也需要实现cloneable接口,比较麻烦。可以将所有的类都实现Serializable接口,通过序列化反序列化实现对象的深度拷贝。
14381441

1439-
### 序列化
1442+
## 序列化
14401443

14411444
序列化:把内存中的对象转换为字节序列的过程称为对象的序列化。
14421445

1443-
#### 什么情况下需要序列化?
1446+
### 什么情况下需要序列化?
14441447

14451448
当你想把的内存中的对象状态保存到一个文件中或者数据库中时候;
14461449
当你想在网络上传送对象的时候;
14471450

1448-
#### 如何实现序列化
1451+
### 如何实现序列化
14491452

14501453
实现Serializable接口即可。序列化的时候(如objectOutputStream.writeObject(user)),会判断user是否实现了Serializable(obj instanceof Serializable),如果对象没有实现Serializable接口,在序列化的时候会抛出NotSerializableException异常。
14511454

1452-
#### serialVersionUID
1455+
### serialVersionUID
14531456

14541457
serialVersionUID 是 Java 为每个序列化类产生的版本标识,可用来保证在反序列时,发送方发送的和接受方接收的是可兼容的对象。类的serialVersionUID的默认值完全依赖于Java编译器的实现。当完成序列化之后,此时对对象进行修改,由编译器生成的serialVersionUID会改变,这样反序列化的时候会报错。可以在序列化对象中添加 serialVersionUID,固定版本号,这样即便序列化对象做了修改,版本都是一致的,就能进行反序列化了。
14551458

1456-
### 遍历
1459+
## 遍历
14571460

1458-
#### fast-fail
1461+
### fast-fail
14591462

14601463
fast-fail是Java集合的一种错误机制。当多个线程对同一个集合进行操作时,就有可能会产生fast-fail事件。
14611464
例如:当线程a正通过iterator遍历集合时,另一个线程b修改了集合的内容,此时modCount(记录集合操作过程的修改次数)会加1,不等于expectedModCount,那么线程a访问集合的时候,就会抛出ConcurrentModificationException,产生fast-fail事件。边遍历边修改集合也会产生fast-fail事件。
@@ -1465,7 +1468,7 @@ fast-fail是Java集合的一种错误机制。当多个线程对同一个集合
14651468
- 使用Colletions.synchronizedList方法或在修改集合内容的地方加上synchronized。这样的话,增删集合内容的同步锁会阻塞遍历操作,影响性能。
14661469
- 使用CopyOnWriteArrayList来替换ArrayList。在对CopyOnWriteArrayList进行修改操作的时候,会拷贝一个新的数组,对新的数组进行操作,操作完成后再把引用移到新的数组。
14671470

1468-
#### fail-safe
1471+
### fail-safe
14691472

14701473
fail-safe允许在遍历的过程中对容器中的数据进行修改。因为采用安全失败机制的集合容器,在遍历时不是直接在集合内容上访问的,而是先copy原有集合内容,在拷贝的集合上进行遍历。
14711474

@@ -1475,7 +1478,7 @@ java.util.concurrent包下的容器都是安全失败的,可以在多线程下
14751478

14761479
fail-safe机制有两个问题:(1)需要复制集合,产生大量的无效对象,内存开销大;(2)不能访问到修改后的内容 。
14771480

1478-
#### 移除集合元素
1481+
### 移除集合元素
14791482

14801483
遍历时安全的移除集合中的元素,要使用遍历器Iterator和iterator.remove()方法。next()必须在remove()之前调用。
14811484

@@ -1492,25 +1495,3 @@ while(iter.hasNext()){
14921495

14931496

14941497

1495-
## 工具类
1496-
1497-
### Arrays.sort()
1498-
1499-
底层原理:
1500-
1501-
1. 判断数组的长度是否大于286,大于则使用归并排序
1502-
1503-
2. 判断数组长度是否小于47,小于则直接采用插入排序,对于小数组来说,插入排序效率更高
1504-
1505-
3. 否则采用双轴快排,使用两个pivot,每轮把数组分成3段,在没有明显增加比较次数的情况下巧妙地减少了递归次数。
1506-
1507-
Collections.sort方法底层就是调用的Arrays.sort方法。
1508-
1509-
### 归并与快速排序
1510-
1511-
归并排序相对而言比较次数比快速排序少,移动次数比快速排序多。
1512-
1513-
对大数组排序。快速排序的sort()采用递归实现,数组规模太大时会发生堆栈溢出,而归并排序sort()采用非递归实现,不存在此问题。
1514-
1515-
快速排序是不稳定的,而归并排序是稳定的。这里的稳定是指比较相等的数据在排序之后仍然按照排序之前的前后顺序排列。
1516-

0 commit comments

Comments
 (0)