diff --git a/README.md b/README.md index 681e1596f5c..bb3f0c06b13 100644 --- a/README.md +++ b/README.md @@ -56,27 +56,27 @@ 4. [代理模式详解:静态代理+JDK/CGLIB 动态代理实战](docs/java/basis/代理模式详解.md) 5. [常见的 IO 模型有哪些?Java 中的 BIO、NIO、AIO 有啥区别?](docs/java/basis/IO模型.md) -### 容器 +### 集合 -1. **[Java 容器常见问题总结](docs/java/collection/Java集合框架常见面试题.md)** (必看 :+1:) -2. **源码分析** :[ArrayList 源码+扩容机制分析](docs/java/collection/ArrayList源码+扩容机制分析.md) 、[LinkedList 源码](docs/java/collection/LinkedList源码分析.md) 、[HashMap(JDK1.8)源码+底层数据结构分析]() 、[ConcurrentHashMap 源码+底层数据结构分析](docs/java/collection/ConcurrentHashMap源码+底层数据结构分析.md) -3. [Java 容器使用注意事项总结](docs/java/collection/Java集合使用注意事项总结.md) +1. **[Java 集合常见问题总结](docs/java/collection/java集合框架基础知识&面试题总结.md)** (必看 :+1:) +2. [Java 容器使用注意事项总结](docs/java/collection/java集合使用注意事项总结.md) +3. **源码分析** :[ArrayList 源码+扩容机制分析](docs/java/collection/arraylist-source-code.md) 、[LinkedList 源码](docs/java/collection/linklist-source-code.md) 、[HashMap(JDK1.8)源码+底层数据结构分析](docs/java/collection/hashmap-source-code.md) 、[ConcurrentHashMap 源码+底层数据结构分析](docs/java/collection/concurrent-hash-map-source-code.md) ### 并发 **知识点/面试题:** (必看 :+1:) -1. **[Java 并发基础常见面试题总结](docs/java/multi-thread/Java并发基础常见面试题总结.md)** -2. **[Java 并发进阶常见面试题总结](docs/java/multi-thread/Java并发进阶常见面试题总结.md)** +1. **[Java 并发基础常见面试题总结](docs/java/multi-thread/java并发基础常见面试题总结.md)** +2. **[Java 并发进阶常见面试题总结](docs/java/multi-thread/java并发进阶常见面试题总结.md)** **重要知识点详解:** -1. **线程池**:[Java 线程池学习总结](./docs/java/multi-thread/java线程池学习总结.md)、[拿来即用的线程池最佳实践](./docs/java/multi-thread/拿来即用的线程池最佳实践.md) -2. [ ThreadLocal 关键字解析](docs/java/multi-thread/万字详解ThreadLocal关键字.md) -3. [并发容器总结](docs/java/multi-thread/并发容器总结.md) -4. [JUC 中的 Atomic 原子类总结](docs/java/multi-thread/Atomic原子类总结.md) -5. [AQS 原理以及 AQS 同步组件总结](docs/java/multi-thread/AQS原理以及AQS同步组件总结.md) -6. [CompletableFuture入门](docs/java/multi-thread/CompletableFuture入门.md) +1. **线程池**:[Java 线程池学习总结](./docs/java/multi-thread/java线程池学习总结.md)、[拿来即用的 Java 线程池最佳实践](./docs/java/multi-thread/拿来即用的java线程池最佳实践.md) +2. [ThreadLocal 关键字解析](docs/java/multi-thread/threadlocal.md) +3. [Java 并发容器总结](docs/java/multi-thread/并发容器总结.md) +4. [Atomic 原子类总结](docs/java/multi-thread/atomic原子类总结.md) +5. [AQS 原理以及 AQS 同步组件总结](docs/java/multi-thread/aqs原理以及aqs同步组件总结.md) +6. [CompletableFuture入门](docs/java/multi-thread/completablefuture-intro.md) ### JVM (必看 :+1:) diff --git "a/docs/java/collection/ArrayList\346\272\220\347\240\201+\346\211\251\345\256\271\346\234\272\345\210\266\345\210\206\346\236\220.md" b/docs/java/collection/arraylist-source-code.md similarity index 100% rename from "docs/java/collection/ArrayList\346\272\220\347\240\201+\346\211\251\345\256\271\346\234\272\345\210\266\345\210\206\346\236\220.md" rename to docs/java/collection/arraylist-source-code.md diff --git "a/docs/java/collection/ConcurrentHashMap\346\272\220\347\240\201+\345\272\225\345\261\202\346\225\260\346\215\256\347\273\223\346\236\204\345\210\206\346\236\220.md" b/docs/java/collection/concurrent-hash-map-source-code.md similarity index 100% rename from "docs/java/collection/ConcurrentHashMap\346\272\220\347\240\201+\345\272\225\345\261\202\346\225\260\346\215\256\347\273\223\346\236\204\345\210\206\346\236\220.md" rename to docs/java/collection/concurrent-hash-map-source-code.md diff --git "a/docs/java/collection/HashMap(JDK1.8)\346\272\220\347\240\201+\345\272\225\345\261\202\346\225\260\346\215\256\347\273\223\346\236\204\345\210\206\346\236\220.md" b/docs/java/collection/hashmap-source-code.md similarity index 100% rename from "docs/java/collection/HashMap(JDK1.8)\346\272\220\347\240\201+\345\272\225\345\261\202\346\225\260\346\215\256\347\273\223\346\236\204\345\210\206\346\236\220.md" rename to docs/java/collection/hashmap-source-code.md diff --git "a/docs/java/collection/Java\351\233\206\345\220\210\346\241\206\346\236\266\345\270\270\350\247\201\351\235\242\350\257\225\351\242\230.md" "b/docs/java/collection/java\351\233\206\345\220\210\346\241\206\346\236\266\345\237\272\347\241\200\347\237\245\350\257\206&\351\235\242\350\257\225\351\242\230\346\200\273\347\273\223.md" similarity index 100% rename from "docs/java/collection/Java\351\233\206\345\220\210\346\241\206\346\236\266\345\270\270\350\247\201\351\235\242\350\257\225\351\242\230.md" rename to "docs/java/collection/java\351\233\206\345\220\210\346\241\206\346\236\266\345\237\272\347\241\200\347\237\245\350\257\206&\351\235\242\350\257\225\351\242\230\346\200\273\347\273\223.md" diff --git "a/docs/java/collection/LinkedList\346\272\220\347\240\201\345\210\206\346\236\220.md" b/docs/java/collection/linklist-source-code.md similarity index 100% rename from "docs/java/collection/LinkedList\346\272\220\347\240\201\345\210\206\346\236\220.md" rename to docs/java/collection/linklist-source-code.md diff --git "a/docs/java/multi-thread/CompletableFuture\345\205\245\351\227\250.md" b/docs/java/multi-thread/completablefuture-intro.md similarity index 100% rename from "docs/java/multi-thread/CompletableFuture\345\205\245\351\227\250.md" rename to docs/java/multi-thread/completablefuture-intro.md diff --git "a/docs/java/multi-thread/synchronized\345\234\250JDK1.6\344\271\213\345\220\216\347\232\204\345\272\225\345\261\202\344\274\230\345\214\226.md" "b/docs/java/multi-thread/synchronized\345\234\250JDK1.6\344\271\213\345\220\216\347\232\204\345\272\225\345\261\202\344\274\230\345\214\226.md" deleted file mode 100644 index c3776c2da21..00000000000 --- "a/docs/java/multi-thread/synchronized\345\234\250JDK1.6\344\271\213\345\220\216\347\232\204\345\272\225\345\261\202\344\274\230\345\214\226.md" +++ /dev/null @@ -1,62 +0,0 @@ -JDK1.6 对锁的实现引入了大量的优化来减少锁操作的开销,如: **偏向锁**、**轻量级锁**、**自旋锁**、**适应性自旋锁**、**锁消除**、**锁粗化** 等等技术。 - -锁主要存在四中状态,依次是: - -1. 无锁状态 -2. 偏向锁状态 -3. 轻量级锁状态 -4. 重量级锁状态 - -锁🔐会随着竞争的激烈而逐渐升级。 - -另外,需要注意:**锁可以升级不可降级,即 无锁 -> 偏向锁 -> 轻量级锁 -> 重量级锁是单向的。** 这种策略是为了提高获得锁和释放锁的效率。 - -### 偏向锁 - -**引入偏向锁的目的和引入轻量级锁的目的很像,他们都是为了没有多线程竞争的前提下,减少传统的重量级锁使用操作系统互斥量产生的性能消耗。但是不同是:轻量级锁在无竞争的情况下使用 CAS 操作去代替使用互斥量。而偏向锁在无竞争的情况下会把整个同步都消除掉**。 - -偏向锁的“偏”就是偏心的偏,它的意思是会偏向于第一个获得它的线程,如果在接下来的执行中,该锁没有被其他线程获取,那么持有偏向锁的线程就不需要进行同步!(关于偏向锁的原理可以查看《深入理解Java虚拟机:JVM高级特性与最佳实践》第二版的13章第三节锁优化。) - -#### 偏向锁的加锁 - -当一个线程访问同步块并获取锁时, 会在锁对象的对象头和栈帧中的锁记录里存储锁偏向的线程ID, 以后该线程进入和退出同步块时不需要进行CAS操作来加锁和解锁, 只需要简单的测试一下锁对象的对象头的MarkWord里是否存储着指向当前线程的偏向锁(线程ID是当前线程), 如果测试成功, 表示线程已经获得了锁; 如果测试失败, 则需要再测试一下MarkWord中偏向锁的标识是否设置成1(表示当前是偏向锁), 如果没有设置, 则使用CAS竞争锁, 如果设置了, 则尝试使用CAS将锁对象的对象头的偏向锁指向当前线程. - -#### 偏向锁的撤销 - -偏向锁使用了一种等到竞争出现才释放锁的机制, 所以当其他线程尝试竞争偏向锁时, 持有偏向锁的线程才会释放锁. 偏向锁的撤销需要等到全局安全点(在这个时间点上没有正在执行的字节码). 首先会暂停持有偏向锁的线程, 然后检查持有偏向锁的线程是否存活, 如果线程不处于活动状态, 则将锁对象的对象头设置为无锁状态; 如果线程仍然活着, 则锁对象的对象头中的MarkWord和栈中的锁记录要么重新偏向于其它线程要么恢复到无锁状态, 最后唤醒暂停的线程(释放偏向锁的线程). - -但是对于锁竞争比较激烈的场合,偏向锁就失效了,因为这样场合极有可能每次申请锁的线程都是不相同的,因此这种场合下不应该使用偏向锁,否则会得不偿失,需要注意的是,偏向锁失败后,并不会立即膨胀为重量级锁,而是先升级为轻量级锁。 - -### 轻量级锁 - -倘若偏向锁失败,虚拟机并不会立即升级为重量级锁,它还会尝试使用一种称为轻量级锁的优化手段(1.6之后加入的)。**轻量级锁不是为了代替重量级锁,它的本意是在没有多线程竞争的前提下,减少传统的重量级锁使用操作系统互斥量产生的性能消耗,因为使用轻量级锁时,不需要申请互斥量。另外,轻量级锁的加锁和解锁都用到了CAS操作。** 关于轻量级锁的加锁和解锁的原理可以查看《深入理解Java虚拟机:JVM高级特性与最佳实践》第二版的13章第三节锁优化。 - -**轻量级锁能够提升程序同步性能的依据是“对于绝大部分锁,在整个同步周期内都是不存在竞争的”,这是一个经验数据。如果没有竞争,轻量级锁使用 CAS 操作避免了使用互斥操作的开销。但如果存在锁竞争,除了互斥量开销外,还会额外发生CAS操作,因此在有锁竞争的情况下,轻量级锁比传统的重量级锁更慢!如果锁竞争激烈,那么轻量级将很快膨胀为重量级锁!** - -### 自旋锁和自适应自旋 - -轻量级锁失败后,虚拟机为了避免线程真实地在操作系统层面挂起,还会进行一项称为自旋锁的优化手段。 - -互斥同步对性能最大的影响就是阻塞的实现,因为挂起线程/恢复线程的操作都需要转入内核态中完成(用户态转换到内核态会耗费时间)。 - -**一般线程持有锁的时间都不是太长,所以仅仅为了这一点时间去挂起线程/恢复线程是得不偿失的。** 所以,虚拟机的开发团队就这样去考虑:“我们能不能让后面来的请求获取锁的线程等待一会而不被挂起呢?看看持有锁的线程是否很快就会释放锁”。**为了让一个线程等待,我们只需要让线程执行一个忙循环(自旋),这项技术就叫做自旋**。 - -百度百科对自旋锁的解释: - -> 何谓自旋锁?它是为实现保护共享资源而提出一种锁机制。其实,自旋锁与互斥锁比较类似,它们都是为了解决对某项资源的互斥使用。无论是互斥锁,还是自旋锁,在任何时刻,最多只能有一个保持者,也就说,在任何时刻最多只能有一个执行单元获得锁。但是两者在调度机制上略有不同。对于互斥锁,如果资源已经被占用,资源申请者只能进入睡眠状态。但是自旋锁不会引起调用者睡眠,如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁,"自旋"一词就是因此而得名。 - -自旋锁在 JDK1.6 之前其实就已经引入了,不过是默认关闭的,需要通过`--XX:+UseSpinning`参数来开启。JDK1.6及1.6之后,就改为默认开启的了。需要注意的是:自旋等待不能完全替代阻塞,因为它还是要占用处理器时间。如果锁被占用的时间短,那么效果当然就很好了!反之,相反!自旋等待的时间必须要有限度。如果自旋超过了限定次数任然没有获得锁,就应该挂起线程。**自旋次数的默认值是10次,用户可以修改`--XX:PreBlockSpin`来更改**。 - -另外,**在 JDK1.6 中引入了自适应的自旋锁。自适应的自旋锁带来的改进就是:自旋的时间不在固定了,而是和前一次同一个锁上的自旋时间以及锁的拥有者的状态来决定,虚拟机变得越来越“聪明”了**。 - -### 锁消除 - -锁消除理解起来很简单,它指的就是虚拟机即使编译器在运行时,如果检测到那些共享数据不可能存在竞争,那么就执行锁消除。锁消除可以节省毫无意义的请求锁的时间。 - -### 锁粗化 - -原则上,我们在编写代码的时候,总是推荐将同步块的作用范围限制得尽量小,——只在共享数据的实际作用域才进行同步,这样是为了使得需要同步的操作数量尽可能变小,如果存在锁竞争,那等待线程也能尽快拿到锁。 - -大部分情况下,上面的原则都是没有问题的,但是如果一系列的连续操作都对同一个对象反复加锁和解锁,那么会带来很多不必要的性能消耗。 - - diff --git "a/docs/java/multi-thread/\344\270\207\345\255\227\350\257\246\350\247\243ThreadLocal\345\205\263\351\224\256\345\255\227.md" b/docs/java/multi-thread/threadlocal.md similarity index 100% rename from "docs/java/multi-thread/\344\270\207\345\255\227\350\257\246\350\247\243ThreadLocal\345\205\263\351\224\256\345\255\227.md" rename to docs/java/multi-thread/threadlocal.md diff --git "a/docs/java/multi-thread/\346\213\277\346\235\245\345\215\263\347\224\250\347\232\204\347\272\277\347\250\213\346\261\240\346\234\200\344\275\263\345\256\236\350\267\265.md" "b/docs/java/multi-thread/\346\213\277\346\235\245\345\215\263\347\224\250\347\232\204java\347\272\277\347\250\213\346\261\240\346\234\200\344\275\263\345\256\236\350\267\265.md" similarity index 100% rename from "docs/java/multi-thread/\346\213\277\346\235\245\345\215\263\347\224\250\347\232\204\347\272\277\347\250\213\346\261\240\346\234\200\344\275\263\345\256\236\350\267\265.md" rename to "docs/java/multi-thread/\346\213\277\346\235\245\345\215\263\347\224\250\347\232\204java\347\272\277\347\250\213\346\261\240\346\234\200\344\275\263\345\256\236\350\267\265.md"