Java虚拟机--线程安全和锁优化
Java虚拟机--线程安全和锁优化
线程安全
线程安全:当多线程访问一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替执行,也不需要额外的同步,或者在调用方进行任何其他的协调操作,调用这个对象的行为都可以获得正确的结果,那么这个对象就是线程安全的。
Java中,线程安全体现在多个线程访问同一个共享数据,如果一段代码中根本不会与其他线程共享数据,可以说不存在线程安全的问题。
线程安全的安全程度,由强至弱排序,可以分为以下5类。
不可变
不可变的对象一定是线程安全的,final关键字可以实现可见性。Java中如果共享数据时基本数据类型,加上final关键字就能保证它不可变,如果是对象,只需保证它是个不可变对象就行,比如String对象,对其的任何操作都不会改变原来的值,而是返回一个新的字符串对象。
绝对线程安全
满足一开始的线程安全定义,即:当多线程访问一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替执行,也不需要额外的同步,或者在调用方进行任何其他的协调操作,调用这个对象的行为都可以获得正确的结果,那么这个对象就是线程安全的。
相对线程安全
通常意义上的线程安全,需要保证这个对象单独操作是线程安全的,在调用时不需要做额外的保障措施,但是对于一些特定顺序的连续调用,就可能使用额外的同步手段。Java API中大多数线程安全类都是这种类型,比如Vector、HashTable等。
线程兼容
指对象本身不是线程安全,但是可以通过使用同步手段保证在并发环境下安全使用。通常说的线程不安全就是指这个类型,Java中大多数类都是,比如ArrayList、HashMap等。
线程对立
无论是否采取了同步措施,都无法在多线程环境中并发安全使用。在Java中很少见。
线程安全的实现方法
互斥同步
同步指在多线程并发访问共享数据时,保证共享的那个数据在同一时刻只能被一个线程使用。。在Java中使用synchronized或者concurrent包中的重入锁可以实现同步。后者相比前者,有一些更高级的功能:
- 等待可中断。当持有锁的线程长时间不释放锁,正在等待的线程可以不在放弃等待,从而可以处理其他任务。
- 公平锁。多个线程等待同一个锁,按照先来后到的顺序依次得到锁。而不是任意一个线程都有机会在这一次能得到锁。synchronized中的锁时非公平的,重入锁ReentrantLock默认非公平,不过可以指定参数设置为公平锁。
- 锁绑定多个条件。一个ReentrantLock可以和多个Condition对象绑定。
性能上,两者差不多。
非阻塞同步
同步会进行线程阻塞,属于悲观策略,即无论是否真的共享数据竞争,都要加锁。而CAS操作属于乐观策略,先进行操作,如果没有共享数据竞争,就操作成功;否则产生冲突,那么就不断重试,直到成功为止。
CAS操作有3个操作数,分别是内存位置V(Java中可简单理解为变量的内存地址)、旧的预期值A,和新值B,当且仅当V符合旧的预期值A时,才会用新值更新V的值,否则不更新,说明这个变量已经被别的线程修改过了。
CAS有个问题:如果变量V一开始被读取到是A值,中途被修改成B,最后又被修改回A,CAS操作会误认为变量V没有被改变过,这称为CAS操作的“ABA问题”。
无同步
如果不涉及共享数据,就无需进行同步。可重入代码:可以在代码执行的任何时刻中断,转而去执行其他代码,在控制权返回后,原来的程序不会出现任何错误。可重入代码都是线程安全的。
锁优化
自旋锁
如果共享数据的锁定状态只有很短的一段时间,为了这段时间去挂起和恢复线程(都需要转入内核态)并不值得,所以此时让后面请求锁的那个线程稍微等待以下,但不放弃处理器的执行时间。这里的等待其实就是执行了一个忙循环,这就是所谓的自旋。
自旋等待有一定的限度,默认值是10次,如果超过这个次数,就会使用传统方式挂起线程。JDK1.6中引入了自适应的自旋锁。如果在同一个对象上,自旋等待刚刚成功获得了锁,且持有的锁正在运行中,虚拟机就认为这次自旋也会成功,进而它被允许有更长时间的自旋等待;相反,如果对于某个锁,自旋很少成功过,那在之后获取这个锁时很可能省略掉自旋过程。
锁消除
虚拟机即时编译时,对一些代码上要求同步,但被检测到不可能存在共享数据竞争的锁进行消除。锁消除的依据来源于“逃逸分析”技术。堆上的所有数据都不会逃逸出去被其他线程访问到,就可以把它们当栈上的数据对待,认为它们是线程私有的,同步加锁就是没有必要的。
锁粗化
如果连续对某个对象反复枷锁或解锁,甚至加锁操作出现在循环中。虚拟机探测到这种情况,会把锁粗化到操作的外部。举个例子
public static int j = 0;
for (int i = 0; i < 100; i++) {
synchronized (this) {
j++;
}
}
// 锁粗化
synchronized (this) {
for (int i = 0; i < 100; i++) {
j++;
}
}
轻量级锁
传统的锁机制称为“重量级”锁,轻量级锁用于在没有多线程竞争的前提下,减少传统的重量级锁使用操作系统互斥量产生的性能消耗。
轻量级锁的加锁和解锁都是通过CAS操作完成的,如果有两个以上的线程争用同一个锁,轻量级锁将膨胀为重量级锁。
轻量级锁能提升同步性能主要因为:对于大多数锁,在整个同步周期内都是不存在竞争的。
偏向锁
轻量级锁噪无竞争的情况下使用CAS操作消除同步使用的互斥量,偏向锁是在无竞争的情况下吧整个同步都消除掉,CAS操作也没有了。
偏向锁会偏向第一个获得它的线程,如果在接下来的执行过程中,该锁没有被其他线程获取,则持有偏向锁的线程永远也不需要再进行同步。
by @sunhaiyu
2018.6.20
Java虚拟机--线程安全和锁优化的更多相关文章
- JVM之java并发 ——线程安全与锁优化
概述 人们很难想象现实中的对象在一项工作进行期间,会被不停地中断和切换,对象的属性(数据)可能会在中断期间被修改和变“脏”,而这些事情在计算机世界中则是很正常的事情.有时候,良好的设计原则不得不向现实 ...
- 深入理解java虚拟机-第13章-线程安全与锁优化
第十三章 线程安全与锁优化 线程安全 java语言中的线程安全 1 不可变.Immutable 的对象一定是线程安全的 2 绝对线程安全 一个类要达到不管运行时环境如何,调用者都不需要额外的同步措施, ...
- 【深入理解JAVA虚拟机】第5部分.高效并发.2.线程安全和锁优化
1 概述 对于这部分的主题“高效并发”来讲,首先需要保证并发的正确性,然后在此基础上实现高效. 2 线程安全 <Java Concurrency In Practice> 的作者Brian ...
- 《深入理解Java虚拟机》-----第13章 线程安全与锁优化
概述 在软件业发展的初期,程序编写都是以算法为核心的,程序员会把数据和过程分别作为独立的部分来考虑,数据代表问题空间中的客体,程序代码则用于处理这些数据,这种思维方式直接站在计算机的角度去抽象问题和解 ...
- 深入理解Java虚拟机(第三版)-14. 线程安全与锁优化
14. 线程安全与锁优化 1. 什么是线程安全? 当多个线程同时访问一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替进行,也不需要进行额外的同步,或者在调用方进行任何其他的协调操作,调用这个 ...
- 《深入了解java虚拟机》高效并发读书笔记——Java内存模型,线程,线程安全 与锁优化
<深入了解java虚拟机>高效并发读书笔记--Java内存模型,线程,线程安全 与锁优化 本文主要参考<深入了解java虚拟机>高效并发章节 关于锁升级,偏向锁,轻量级锁参考& ...
- JVM-并发-线程安全与锁优化
线程安全与锁优化 1.线程安全 (1)当多个线程访问一个对象时,如果不考虑这些线程在执行时环境下的调度和交替执行,也不需要进行额外的同步,或者在调用方进行任何其他的协调操作,调用这个对象的行为都可以获 ...
- jvm(13)-线程安全与锁优化(转)
0.1)本文部分文字转自“深入理解jvm”, 旨在学习 线程安全与锁优化 的基础知识: 0.2)本文知识对于理解 java并发编程非常有用,个人觉得,所以我总结的很详细: [1]概述 [2]线程安全 ...
- 深入理解JVM(7)——线程安全和锁优化
Java中的线程安全 按照线程安全的“安全程度”由强至弱来排序,可以将Java语中各种操作共享的数据分为以下5类:不可变. 绝对线程安全. 相对线程安全. 线程兼容和线程对立. 1.不可变 不变的对象 ...
随机推荐
- centos部署yapi爬坑记
前言 这几天终于完成了为期三个月的公司某个demo版的项目,在这期间和公司的后台因为API的事怼过无数次了,'我的接口没问题,是你请求的方式不对吧!'.'一定是你请求的参数不对'......诸如此类问 ...
- WPF自定义TabControl样式
WPF自定义TabControl,TabControl美化 XAML代码: <TabControl x:Class="SunCreate.Common.Controls.TabCont ...
- Distinct Substrings(spoj694)(sam(后缀自动机)||sa(后缀数组))
Given a string, we need to find the total number of its distinct substrings. Input \(T-\) number of ...
- 控制台API函数----HANDLE、SetConsoleCursorPosition、SetConsoleTextAttribute
控制台API函数 调用相关文本界面控制的API函数,这些函数可分为三类. 一.用于控制台窗口控制的函数(包括窗口的缓冲区大小.窗口前景字符和背景颜色.窗口标题.大小和位置等): 二.用于控制台输入输出 ...
- [转载]java开发中的23种设计模式
原文链接:http://blog.csdn.net/zhangerqing 设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反 ...
- 如何执行超过一百兆(100MB)的sql脚本?
最近遇到一个问题,在sqlserver的查询分析器里面执行一个超过100MB的数据库脚本,发现老是报“引发类型为“System.OutOfMemoryException”的异常”,上网查了一下,主要是 ...
- Swift5 语言指南(二十七) 访问控制
访问控制限制从其他源文件和模块中的代码访问部分代码.此功能使您可以隐藏代码的实现细节,并指定一个首选接口,通过该接口可以访问和使用该代码. 您可以为各个类型(类,结构和枚举)以及属于这些类型的属性,方 ...
- 创建python3虚拟环境指令和冻结所安装的包
mkvirtualenv file_name -p python3 去掉后面的 P 和python3 代表创建python2环境 其中p代表路径的意思 冻结所安装包命令 pip freeze > ...
- Pycharm配置autopep8:自动调整代码为PEP8风格
关于PEP 8 PEP 8,Style Guide for Python Code,是Python官方推出编码约定,主要是为了保证 Python 编码的风格一致,提高代码的可读性. 官网地址:http ...
- 微信公众平台主动推送消息(asp.net)
/// <summary> /// MD5 32位加密 /// </summary> /// <param name=" ...