多线程 第四节 Java 虚拟机对 synchronized 的优化

1、 synchronized 相对于 volatile 是重量了很多,因此在以前很让人诟病,但是从 JDK 1.6 版本以后为了减少获得锁和释放锁带来的性能消耗而引入了偏向锁和轻量级锁,以及锁的存储结构和升级过程。
2、 在 Java SE 1.6 中,锁一共有4种状态,级别从低到高依次是:无锁状态、偏向锁状态、轻量级锁状态、重量级锁状态
3、 这四种状态会随着竞争情况逐渐升级。锁可以升级但不能降级
4、 这是因为,自旋锁无法预知到底会空循环几个时钟周期,并且会很消耗 CPU,为了避免这种无用的自旋操作,一旦锁升级为重量锁,就不会再恢复到轻量级锁
5、 锁升级却不能降级的策略,目的是为了提高获得锁和释放锁的效率。
6、 偏向锁的核心思想是:如果一个线程获得了锁,那么锁就进入了偏向模式。当这个线程再次请求锁时,无需再做任何同步操作,这样就节省了大量有关锁申请的操作,从而提高了程序的性能。
7、 偏向锁获取锁流程:GitChat13课
8、 对于只有一个线程访问的同步资源场景,锁的竞争不是很激烈,这时候使用偏向锁是一种很好的选择,因为连续多次极有可能是同一个线程请求相同的锁。
9、 在锁竞争比较激烈的场景,最有可能的情况是每次不同的线程来请求相同的锁,这样的话偏向锁就会失效,倒不如不开启这种模式,幸运的是 Java 虚拟机提供了参数可以让我们有选择的设置是否开启偏向锁。
10、 偏向锁升级为轻量锁:如果偏向锁失败,虚拟机并不会立即挂起线程,而是使用轻量级锁进行操作。
11、 轻量级锁他只是简单的将对象头部作为指针,指向持有锁的线程堆栈的内部,来判断一个线程是否持有对象锁。
12、 如果线程获得轻量级锁成功,则可以顺利进入临界区。如果轻量级锁加锁失败,则表示其他线程抢先夺到锁,那么当前线程的轻量级锁就会膨胀为重量级锁。
13、 自旋锁:假设在不就的将来,就可以得到锁,因此虚拟机会让当前线程做几个空循环(这也就是自旋锁的意义),若经过几个空循环可以获取到锁则进入临界区,如果还是获取不到则系统会真正的挂起线程。
14、 锁消除是在编译器级别的事情。在即时编译器时,如果发现不可能被共享的对象,则可以消除这些对象的锁操作。
15、 上下文切换:任务从保存到再加载的过程
16、 无锁正是一种减少上下文切换的技术 
17、 对于并发控制而言,锁是一种悲观的策略,无锁是一种乐观的策略。
18、 无锁的策略使用一种叫做比较交换的技术(CAS Compare And Swap)来鉴别线程冲突,一旦检测到冲突产生,就重试当前操作直到没有冲突为止。
19、 无锁的方式完全没有锁竞争带来的系统开销,也没有线程间频繁调度带来的开销,因此比基于锁的方式拥有更优越的性能。
20、 无锁的好处:
第一,在高并发的情况下,它比有锁的程序拥有更好的性能;
第二,它天生就是死锁免疫的。
21、 CAS 算法的过程是这样:它包含三个参数 CAS(V,E,N): V 表示要更新的变量,E 表示预期值,N 表示新值。仅当 V 值等于 E 值时,才会将 V 的值设为 N,如果 V 值和 E 值不同,则说明已经有其他线程做了更新,则当前线程什么都不做。最后,CAS 返回当前 V 的真实值。
 

多线程 第四节 Java 虚拟机对 synchronized 的优化_第1张图片

 

你可能感兴趣的:(多线程,多线程,java)