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 ...
随机推荐
- javascript面向对象系列第四篇——OOP中的常见概念
前面的话 面向对象描述了一种代码的组织结构形式——一种在软件中对真实世界中问题领域的建模方法.本文将从理论层面,介绍javascript面向对象程序程序(OOP)中一些常见的概念 对象 所谓对象,本质 ...
- 多线程 - pthread、NSThread
1. pthread pthread 简单介绍下,pthread是一套通用的多线程的API,可以Unix / Linux / Windows 等徐彤跨平台使用,使用C语言编写,需要程序员自己管理线程的 ...
- pymysql实现MySQL与Python交互
常见MySQL操作 所需模块: pip3 install pymysql 查询(fetchone,fetchmany,fetchall): import pymysql #连接 con = pymys ...
- javascript设计模式——发布订阅模式
前面的话 发布—订阅模式又叫观察者模式,它定义对象间的一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知.在javascript开发中,一般用事件模型来替代传统的发布—订阅模 ...
- 【机器学习】RNN学习
感谢中国人民大学的胡鹤老师,课程容量巨大,收获颇丰. 之前提到的CNN模型主要用到人类的视觉中枢,但其有一劣势,无论是人类的视觉神经还是听觉神经,所接受到的都是一个连续的序列,使用CNN相当于割裂了前 ...
- Android测试:Fundamentals of Testing
原文地址:https://developer.android.com/training/testing/fundamentals.html 用户在不同的级别上与你的应用产生交互.从按下按钮到将信息下载 ...
- 基于Java使用Snmp4j进行监控与采集(snmptrap、snmpwalk、snmpget)
之前有在弄监控服务器这块的工作,今天来整体总结下.因为有些服务器(路由器.交换机等都是基于snmp协议的)必须使用snmp协议去监控采集和接收信息,所以必须去了解snmp相关内容,以及如何在基于jav ...
- Express4.x API (四):Router (译)
Express4.x API 译文 系列文章 Express4.x API (一):application (译) -- 进行 Express4.x API (二):request (译) -- 完成 ...
- Spark Shuffle模块——Suffle Read过程分析
在阅读本文之前.请先阅读Spark Sort Based Shuffle内存分析 Spark Shuffle Read调用栈例如以下: 1. org.apache.spark.rdd.Shuffled ...
- LeetCode139:Word Break
Given a string s and a dictionary of words dict, determine if s can be segmented into a space-separa ...