Java并发之底层实现原理学习笔记
本篇博文将介绍java并发底层的实现原理,我们知道java实现的并发操作最后肯定是由我们的CPU完成的,中间经历了将java源码编译成.class文件,然后进行加载,然后虚拟机执行引擎进行执行,解释为汇编语言,然后转为操作系统指令,然后转为1,0,最后CPU进行识别执行。
提到java的并发,我们不由的就会想到java中常见的键字:volatile和synchronized,我们接下来就会从这两个关机字展开分析:
- volatile的底层实现原理
- synchronized的实现原理和应用
volatile
说到volatile,在java的面试中面试官可是最喜欢问的问题了。看到它我们首先想到的便是保持线程间的可见性,是一个轻量级的synchronized,在一些情况下它可以代替synchronized。
volatile的作用:
一个被volatie修饰的变量,java内存模型会保证所有的线程看见的变量值是一致的。
volatile的工作原理:
我们可以定义一个volatile变量,并对他进行赋值,并通过工具来获取jit编译器生成的汇编指令,我们会发现在对volatile变量进行写操作时,会多出一条指令:以lock为前缀的指令:
lock为前缀的指令在多核处理器下回引发两件事情:
①将当前处理器缓存行的数据回写到内存中。
②这个回写内存的操作会使得在其他cpu里缓存了改内存地址的数据无效。
当我们知道了以上两点,我们就不难理解volatie变量的机制了。
在多处理器下,为了保证各个处理器的缓存是一致的,会实现缓存一致性协议,每个处理器通过嗅探在总线上的传播的数据来检查自己缓存的值是不是过期了。
synchronized
想到多线程的并发,其实我第一个想到的便是这个synchronized,翻译过来为同步,我们都知道它是一个重量级锁,当对一个方法或者代码块使用它时,当一个线程获得了这个锁,那么其它的线程就会陷入挂起状态,在java中也就表现为sleep状态,我们都知道线程的挂起和运行时要转入操作系统的内核态的(与内核态对应的便是用户态),这样特别浪费cpu资源,所以这个重量级锁是名副其实的!
但是,java SE 1.6过后java的维护团队对它进行了一系列的优化(这些优化后面一一讲述),他也就没那么“重”了,以前还有优势的可重入锁也变得没那么有优势了(ReentrantLock)。
一下我们就下列几个方面讲述synchronized:
- 利用synchronized实现同步的基础
- synchronized是如何实现锁的
- 偏向锁,轻量级锁(自旋锁),重量级锁
- 锁的升级
- java如何实现原子操作
①利用synchronized实现同步的基础:
我们在开发中或者java的源码中都能看见synchronized的身影,例如HashTable,StringBuilder等地方,常见有两种方式:
Ⅰ丶同步方法
同步方法只需要在方法前加上synchronized便可,当一个线程执行它的时候其他线程便会陷入等待,直到它释放锁。对方法使用又可以分为两种:对普通同步方法和对静态方法,它们之间的差别是加锁的对象不同,普通方法加锁的位置是当前的对象,而静态方法加锁的位置是当前类的Class对象。
Ⅱ丶同步方法块
同步方法块加锁的是Synchronized后括号里配置的对象,这个对象可以是一个值以及任何一个变量或者对象。
②synchronized是如何实现锁的:
在jvm的规范中可以看到synchronized在jvm中的实现原理,jvm基于进入和退出Monitor对象来实现同步方法和代码块的同步,代码块是使用monitorenter和monitorexit指令来实现的,而同步方法jvm规范里没有具体给出,但是我相信具体的原理应该相差不大,无非是将java源码编译为class文件,在class字节码文件中对使用synchronized的方法进行一个标记,在字节码引擎执行这个方法的时候会对这个方法进行同步处理。
③偏向锁,轻量级锁(自旋锁),重量级锁:
在讲锁之前我们需要知道java对象头,java的对象头:
synchronized使用的锁是存储在java对象头里的,java对象头里面有32bit/64bit(视操作系统的位数而定)长度的MarkWord 里面存储了对象的hashCode和锁的信息等,在MarkWord中有2bit的空间来表示锁的状态00,01,10,11,分别表示轻量级锁,偏向锁,重量级锁,GC标记。
偏向锁:偏向锁也就人称它为偏心锁,从名字我们就可以看出来,它是一个偏向某一个线程的锁。
在实际的开发中,我们发现多线程并发,大多数执行同步方法的都是同一个线程,出现多个线程争抢一个方法的概率比较低,所以重复的获取锁和释放锁就会产生大量的资源浪费,所以为了让线程获得锁的代价更低引入了偏向锁,当一个线程访问一个同步块并获得锁时,会在对象头和线程的栈帧中的锁记录中存储偏向锁的线程ID,以后该线程进入和退出同步块时不需要进行CAS操作来进行加锁和解锁,只需要简单的查看对象头的MarkWord里是否还存有指向当前的偏向锁(在MarkWord中每个对象还有一个偏向锁标志位用来表示当前对象是否支持偏向锁,我们可以使用jvm参数来设定偏向锁)。
关于偏向锁的释放,偏向锁使用了等到存在竞争时才释放锁的机制,所以当有其他线程尝试竞争偏向锁的时候持有偏向锁的线程才会释放锁。
注意:在java6,7中偏向锁是默认启动的
轻量级锁:
轻量级锁就是在执行同步块之前,jvm会在当前线程的栈帧中创建用于存储锁记录的的空间,并将对象头中的MarkWord复制到里面,然后线程将尝试将对象头内的MarkWord替换为指向锁记录的指针,如果成功,当前线程获得锁,如果失败,表示其他线程竞争锁,当前线程便自旋来获得锁。
④锁的升级:
当前线程如果无法试用上面的方法获得锁,那么表示当前的锁存在竞争,锁就会升级为重量级锁。
轻量级锁和偏向锁的区别:
轻量级锁是在无竞争的情况下使用CAS操作去消除同步使用的互斥量,而偏向锁就是在无竞争的情况下把整个同步都去除,连CAS操作都不做!
⑤ java如何实现原子操作:
在了解java是如何实现原子操作之前,我们要知道处理器是如何实现原子操作的:
处理器一般分为两种方法执行原子操作:缓存加锁和总线加锁,其中缓存加锁比较优秀而总线加锁则比较消耗资源。(关于两种加锁的方式我们这里不做过多解释,具体在操作系统中有详细的讲解)
java使用(大多数情况下)循环CAS实现原子操作,但是使用CAS实现原子操作也会出现下面的一些经典的问题:
一)ABA问题
jdk中提供AtomicStampedReference类来解决(提供检查预期引用和预期标志)
二)循环时间长开销大
无法解决,这个是循环的通病
三)只能保证一个共享变量的原子操作
jdk中提供一个AtomicReference来解决,将多个共享变量放置在一个类中进行CAS操作。
以上为自己学习的笔记和一些自己的感想,以便博主以后查阅,也供大家参考如果错误和侵权还请联系我,改正,侵删!
参考书籍:《并发编程的艺术》
Java并发之底层实现原理学习笔记的更多相关文章
- 深入理解Java并发之synchronized实现原理
深入理解Java类型信息(Class对象)与反射机制 深入理解Java枚举类型(enum) 深入理解Java注解类型(@Annotation) 深入理解Java类加载器(ClassLoader) 深入 ...
- 20145213《Java程序设计》第八周学习笔记
20145213<Java程序设计>第八周学习笔记 教材学习内容总结 "桃花春欲尽,谷雨夜来收"谷雨节气的到来意味着寒潮天气的基本结束,气温回升加快.刚出冬的我对于这种 ...
- Java AOP的底层实现原理
Java AOP的底层实现原理 一.什么是AOP 1.AOP:Aspect Oriented Programming(面向切面编程),OOP是面向对象编程,AOP是在OOP基础之上的一种更高级的设计思 ...
- Java volatile 关键字底层实现原理解析
本文转载自Java volatile 关键字底层实现原理解析 导语 在Java多线程并发编程中,volatile关键词扮演着重要角色,它是轻量级的synchronized,在多处理器开发中保证了共享变 ...
- Java架构师-十项全能学习笔记(1)
Java架构师-十项全能学习笔记(1) @Configuration @EnableStateMachine public class OrderStateMachineConfig extends ...
- 【java并发编程艺术学习】(三)第二章 java并发机制的底层实现原理 学习记录(一) volatile
章节介绍 这一章节主要学习java并发机制的底层实现原理.主要学习volatile.synchronized和原子操作的实现原理.Java中的大部分容器和框架都依赖于此. Java代码 ==经过编译= ...
- Java架构师之路 Spring学习笔记(一) Spring介绍
前言 这是一篇原创的Spring学习笔记.主要记录我学习Spring4.0的过程.本人有四年的Java Web开发经验,最近在面试中遇到面试官总会问一些简单但我不会的Java问题,让我觉得有必要重新审 ...
- Unity3D 骨骼动画原理学习笔记
最近研究了一下游戏中模型的骨骼动画的原理,做一个学习笔记,便于大家共同学习探讨. ps:最近改bug改的要死要活,博客写的吭哧吭哧的~ 首先列出学习参考的前人的文章,本文较多的参考了其中的表述: 1. ...
- j2ee开发之Spring2.5框架学习笔记
Spring 2.5框架学习笔记 1.是一个开源的控制反转IOC和面向切面AOP的容器框架 2.IOC控制反转 public class PersonServiceBean { private Per ...
随机推荐
- 封装及propery的使用
封装 封装的目的 使类中的属性或者方法只允许在类内部使用,不允许外部对其访问,保证数据的安全性. 封装的方法 使属性或者函数名改写成:"__属性名或者函数名"的格式,即完成了对本类 ...
- CSS的常见问题
1.css的编码风格 多行式:可读性越强,但是CSS文件的行数过多,影响开发速度,增大CSS文件的大小 一行式:可读性稍差,有效减少CSS文件的行数,有利于提高开发速度,减小CSS文件的大小 2.id ...
- 【NOIP2012提高组】借教室
90分暴力解法: 用线段树,初始值为该天的教室数,每个人来申请的时候在这段区间减去借走的数,然后查询最小值是否小于0,是就输出-1,否则继续. (其实在vijos是可以直接A的,他们的评测机太快了) ...
- java.util.ArrayList、java.util.vector和java.util.LinkedList (JDK 1.8.0_111)
一.java.util.ArrayList 1.1 ArrayList 继承结构 ArrayList实现了RandomAccess,可以随机访问(其实就是通过数组下标访问):实现了Cloneable, ...
- log4j2 项目日志组件
在项目运行过程中,常常需要进行功能调试以及用户行为的跟踪和记录,部分人习惯使用System.out,但这并不建议,它仅仅是使用方便但不便于维护也无扩展性.相比log4j的话,log4j可以控制日志信息 ...
- Xcode6 UIWebView与JavaScript交互(issue fix)
这篇文章中,有介绍UIWebView与JavaScript交互,在UIWebView截获JavaScript请求处理.从app的角度,这是JavaScript的Hook请求. 在Xcode6之前的Ap ...
- Vue深度学习(4)-方法与事件处理器
方法处理器 可以用 v-on 指令监听 DOM 事件: <div id="app"> <button v-on:click = "greet" ...
- 十一、Spring Boot 集成Shiro和CAS
1.Shiro 是什么?怎么用? 2.Cas 是什么?怎么用? 3.最好有spring基础 首先看一下下面这张图: 第一个流程是单纯使用Shiro的流程. 第二个流程是单纯使用Cas的流程. 第三个图 ...
- 10个最有用的 IntelliJ IDEA 插件
IntelliJ IDEA鼓舞了许多Java开发人员编写插件,从J2EE到代码编辑工具再到游戏.现在,它拥有了一个强大的插件生态系统,超过1500可用的插件以及几乎每周都有新的插件出现.在这篇文章中, ...
- IntelliJ IDEA 2017 注册方法
本文使用破解方式注册. JetbrainsCrack-2.6.2.jar适用于ideaIU-2017.2.之前版本,若下载的版本较新破解文件可能无法使用,破解时一闪而退. 其中JetbrainsCra ...