Java 线程 — synchronized、volatile、锁
线程同步基础
synchronized 和volatile是Java线程同步的基础。
synchronized
将临界区的内容上锁,同一时刻只有一个进程能访问该临界区代码
使用的是内置锁,锁一个时刻只能被一个线程持有,可以重入(表示一个处于synchronized代码中的线程可以进入另外一个使用synchronized的代码快,比如:方法A和方法B同时使用synchronized修饰,在方法A中调用了方法B,调用某个线程调用方法A的时候不会造成死锁,因为synchronized是可重入的锁,线程在进入方法A的时候获得了当前对象的锁,但是此时这个线程依然可以获得方法B的synchronized锁)
synchronized修饰不同对象时获得的锁:
- 修饰普通方法:获得的锁是当前对象
- 修饰静态方法:获得的锁是当前类class
- 修饰代码块:取决于具体的锁对象
在Java的同步方法中synchronized是比较重量级的锁,而且不够灵活,jvm提供了更轻量的volatile,jdk提供了更灵活的Lock。
volatile
在多处理器的CPU架构下,因为每个处理器都有自己的缓存,线程访问变量的时候会读取缓存,多个线程读取的缓存不一样会导致每个线程得到的值不一样。使用该关键字的效果是:
- 处理器将缓存写回到内存
- 处理器将缓存写回到内存的时候会导致其他处理器的内存失效
作用
- 保证可见性,Java内存模型(JMM)确保所有线程看到的这个变量的值是一致的
- 只保证简单操作的原子性(保证变量简单赋值操作的原子性,如:temp = 1,不保证复杂操作的原子性,如:temp++)
内存语义(就是内存会做的操作)
- 写:当写一个volatile的变量时,JMM把该线程对应的本地缓存中的共享变量刷新到主内存
- 读:当读一个volatile变量时,JMM把该线程对应的本地缓存置为无效,线程接下来将从主存中读取共享变量
问题:上面提到的刷新操作是对这个本地内存刷新,还是只刷新volatile变量?
解答:是刷新整个本地缓存,包括其他共享变量
CAS
CAS:Compare And Switch,在Java中是通过调用C/C++写的本地方法完成的,C又调用了CPU的cmpxchg指令完成的。
一般来说有三个值:内存值V,期望值A,更新值B,如果内存值和期望值相等,则用更新值B替换内存值A,否则什么也不做
锁
什么叫锁:锁其实就是维护一种状态,比如一个int状态值state,state变量对于所有线程可见,线程A将state改为1的时候(假设,当然根据具体的需要可以设为对应的值)表示上锁的状态,线程在试图修改state的时候,发现是1,说明其他线程已经改过,线程B则进入阻塞状态,当线程A释放锁的时候,也就是将state改为0的时候,唤醒线程B,线程B会重新试图获取锁,也就是修改state的值,如果state为0,那么修改成功,线程B获得锁
- 偏向锁:为了让之前获得过该锁的线程更容易获得锁(获得锁的代价更低,不需要CAS加锁和解锁),因为Hotspot的作者研究发现:大多数情况下锁不仅不存在竞争,而且总是由同一线程多次获得
内存语义
- 获取锁:当线程获取锁时,JMM会把线程对应的本地缓存中的共享变量刷新到主存
- 释放锁:当线程释放锁时,JMM会把线程对应的本地缓存置为无效
对比volatile的和锁的内存语义,volatile的写——锁的获取,volatile的读——锁的释放
释放锁的线程在释放锁之前可见的变量,在获取锁的线程获取锁之后也可以看见这些变量,volatile也一样
锁的实现
- 利用volatile的读-写内存语义
- 利用CAS(CompareAndSet)附带的volatile读-写内存语义(因为在实现CAS的时候汇编会有一个lock前缀,这个前缀会带来和volatile相同的内存语义)
一些零碎的知识点:
- JVM在类初始化阶段(Class加载后,且被线程使用前),JVM会获取一个锁,这个锁可以同步多个线程对同一个类的初始化
Java 线程 — synchronized、volatile、锁的更多相关文章
- Java 线程安全 与 锁
Java 线程安全 与 锁 多线程内存模型 线程私有栈内存 每个线程 私有的内存区域 进程公有堆内存 同一个进程 共有的内存区域 为什么会有线程安全问题? 多个线程同时具有对同一资源的操作权限,又发生 ...
- 【Java线程安全】锁
Java都有哪些锁? synchronized 和 reentranlock是最常见的,其中前者又JVM提供实现,后者有专门对应的java.util.concurrent包提供:同时后者功能更加丰富. ...
- Java线程同步与锁
一.synchronized synchronized锁什么?锁对象.可能锁对象包括: this, 临界资源对象,Class类对象. 1,同步方法 synchronized T methodName( ...
- Java线程安全与锁优化
线程安全的严谨定义: 当多个线程访问一个对象时,如果不用考虑这些线程在运行时环境下的调度和交题执行,也不需要进行额外的同步,或者调用方法进行其他任何操作,调用这个对象的行为都可以或者正确的结果,那么这 ...
- 【Thread】java线程之对象锁、类锁、线程安全
说明: 1.个人技术也不咋滴.也没在项目中写过线程,以下全是根据自己的理解写的.所以,仅供参考及希望指出不同的观点. 2.其实想把代码的github贴出来,但还是推荐在初学的您多亲自写一下,就没贴出来 ...
- Java线程安全与锁优化,锁消除,锁粗化,锁升级
线程安全的定义 来自<Java高并发实战>"当多个线程访问一个对象的时候,如果不用考虑这些线程在运行时环境下的调度和交替执行,也不需要进行额外的同步,或者在调用方法的时候进行任何 ...
- 【Java线程】volatile的适用场景
http://www.ibm.com/developerworks/cn/java/j-jtp06197.html 把代码块声明为 synchronized,有两个重要后果,通常是指该代码具有 原子性 ...
- java多线程synchronized volatile解析
先简单说说原子性:具有原子性的操作被称为原子操作.原子操作在操作完毕之前不会线程调度器中断.即一个操作或者多个操作 要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行.在Java中,对除了l ...
- Java线程synchronized(一)
线程安全概念:当多个线程访问某一个类(对象或方法)时,这个对象始终都能表现出正确的行为,那么这个类(对象或方法)就是线程安全的. synchronized:可以在任意对象及方法上加锁,而加锁的这段代码 ...
随机推荐
- LINK : fatal error LNK1104: 无法打开文件“gtestd.lib”
解决办法: 复制编译出来的gtestd.lib文件到D:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\lib目录下 我这里用的是vs2015 ...
- javascript学习第一课
1.基本知识: 1.1 词法结构 1.1.1 字符集 javascript程序是用Unicode字符集编写的. 1.1.2 区分大小写 javascript是区分大小写的语言.也即是关键字.变量.函数 ...
- Til the Cows Come Home
Description Bessie is out in the field and wants to get back to the barn to get as much sleep as pos ...
- Repeater 使用方法
ItemTemplate: 包含要逐一呈现给数据源中的每个数据项的 HTML 元素和控件 AlternatingItemTemplate: 包含要逐一呈现给数据源中的其他每个数据项的 HTML 元素和 ...
- Linux上设置nginx支持https
1.前提条件 如果系统没有自带openssl,则需要安装. 2.生成证书 # .首先,进入你想创建证书和私钥的目录,例如: cd /etc/nginx/ # .创建服务器私钥,命令会让你输入一个口令: ...
- C2第七次作业解题报告
看过题解后如果觉得还算有用,请帮忙加点我所在团队博客访问量 http://www.cnblogs.com/newbe/ http://www.cnblogs.com/newbe/p/4069834.h ...
- jquery 编码解码
中文转Unicode:HttpUtility.UrlEncodeUnicode(string str); 转换后中文格式:"%uxxxx" 举例:"柳_abc123&qu ...
- delphi中获取调用堆栈信息
异常堆栈有利于分析程序的错误,Delphi的Exception有StackTrace属性,但是值为空,因为StackTrace的信息收集Delphi委托给了第三方组件来完成,真是脑子有毛病! 借助于m ...
- C++ Base64 编码 解码
C++实现 base64 字符串编码解码(GCC编译). /** * @brief C++ base64 编解码 * @author wid * @date 2013-20-25 * * @note ...
- [MSSQL]如何高效查询表的总记录数
如何高效查询表的总记录数?[总结-整理-马克] 首先想到的自然是在表主键上应用COUNT函数来查询了,这个是目前使用最多的方法,没有之一 ) ROWS FROM product 这里再给出一些其它方法 ...