线程安全的严谨定义:

当多个线程访问一个对象时,如果不用考虑这些线程在运行时环境下的调度和交题执行,也不需要进行额外的同步,或者调用方法进行其他任何操作,调用这个对象的行为都可以或者正确的结果,那么这个对象是线程安全的!

java共享数据分类(5类

1)不可变

2)绝对线程安全:不管运行环境如何,调用者都不需要任何额外的同步措施,java api中标注自己是线程安全的类,都不是绝对线程安全的

3)相对线程安全:就是我们通常意义上讲的线程安全,需要保证对这个对象的单独操作是线程安全的,我们在调用的时候不需要做额外的保障措施,但对于一些特定顺序的连续调用就需要调用端使用额外的保障措施,比如vector的线程安全的容器,其add,get,size方法都被synchronized修饰,但是当另外一个线程恰好在错误的时间删除一个元素,导致该元素已经不再可用的话,就会产生异常,余姚对删除元素操作锁定一下

4)线程兼容:指对象本身不是线程安全的,但是可以通过在调用端正确的使用同步手段保证对象在多线程环境下是线程安全的,我们平常说的一个类不是线程安全的,通常指的就是这种情况

5)线程对立:无论是否采取同步措施,都无法并发执行,比如两个不同的线程同时持有一个线程对象,一个尝试去中断线程,一个尝试去恢复线程,这种情况无论是否采取同步措施,都无法并发执行,还存在死锁的风险

线程安全的实现方法:

1.互斥同步(悲观锁,最大的问题就是线程阻塞和唤醒带来的性能问题)

1.1最基本的互斥同步就是synchroized关键字(可重入锁,非公平锁)(重量级锁,线程阻塞唤醒开销大)

一点优化:在通知系统阻塞线程前加入一段自旋等待过程,避免频繁切换到核心态

1.2 ReentrantLock(也是重入锁,默认下非公平锁),需要lock,unlock方法配合try/finally完成操作,相比于synchronized,ReentrantLock增加了3个高级功能:可中断,可实现公平锁,以及锁可以绑定多个条件

注意:多线程环境下,synchronized的吞吐量下降得厉害,而ReentrantLock则能基本保证在一个稳定水平,是因为synchronized还要很多优化的余地!!

2.非阻塞同步(乐观锁,基于冲突检测的乐观并发策略)

通俗的说,就是先进行操作,如果没有其他线程竞争共享数据,那操作就成功了,如果共享数据有争用,产生了冲突,就是采取其他措施(最常见的就是不断的重试,直到成功,CAS机制),这种措施不需要挂起线程

从硬件方面保证操作和冲突检测具备原子性(unsafe类)

重量级锁的锁优化技术(Synchronized):

1.自旋锁:某个线程占用了共享数据,本线程先不挂起,而是处于自旋等待状态,不断重试

自旋的次数有限制,不然一直自旋会消耗系统资源

自适应自旋:如果某个锁,自旋很少成功获得,那么以后要获取这个锁时将可能省略掉自旋过程,以避免浪费处理器资源

2.锁消除:指JVM运行时,对一些代码上要求同步,但被检测到不可能存在共享数据竞争的锁进行消除

3.锁粗化:如果一系列的连续操作都对同一个对象反复加锁解锁,甚至是加锁操作出现在循环体中,那即使没有竞争,频繁的进行互斥同步操作也会导致不必要的性能消耗,这个时候将锁的范围扩展,变成一个锁,就是锁的粗化

4.轻量级锁:与Mark Word和CAS机制有关

轻量级锁能提供性能的依据:对于绝大部分,在整个同步周期内是不存在竞争的,这是一个经验数据

Mark Word的组成:

轻量级锁的加锁过程:

1)在代码进入同步块的时候,如果同步对象锁为无锁状态(锁标志位为01状态),虚拟机首先在当前线程的栈帧中建立一个名为锁记录(Lock Record)的空间,用于存储旧的Mark Work的拷贝(锁记录解锁的时候用到)

2)虚拟机使用CAS机制尝试将对象的Mrak Word更新为轻量级锁的标志位和指向锁记录的指针

3)如果更新操作成功,那么线程就拥有了该对象的锁

4)如果这个更新操作失败,虚拟机首先会检查当前线程是否已经有了这个对象的锁,如果已经有了,就进入同步代码块继续执行,如果没有就说明该对象的锁被其他线程占用了,一旦这样,轻量级锁就膨胀成为重量级锁(比如synchronized),Mark Work中存储的就指向重量级锁的指针,后面等待锁的线程也会进入等待状态

轻量级锁的解锁过程:

1).通过CAS机制尝试将当前线程栈帧中的锁记录替换当前的Mark Word

2).如果替换成功,那么整个同步过程就完成了

3).如果替换失败,则说明有其他线程尝试获取过该锁,但失败了,导致轻量级锁变成了重量级锁,那么要在释放锁的同时,唤醒被挂起的线程

总结:轻量级锁就是在无竞争的情况下使用CAS操作区消除同步使用的互斥量

5.偏向锁:在无竞争的情况下,把整个同步过程都消除掉,连CAS操作都不做

偏向锁的依据:锁总是同一个线程持有,很少发生竞争

偏向锁偏向于第一个获得它的线程,如果在接下来的指向过程中,该锁没有被其他线程获取,则持有偏向锁的线程永远不需要进行同步

做法:只需要在锁第一个被拥有的时候,记录下偏向线程ID,这样偏向线程就一直持有着锁,直到竞争发生才释放锁,以后每次同步,检查锁的偏向线程ID是否与当前线程ID一致,如果一致直接进入同步,退出同步也无需每次加锁解锁都去CAS更新Mark Word,如果不一致则意味着发生了竞争,锁已经不总是偏向于一个线程了,这时候锁膨胀为重量级锁才能保证线程公平竞争锁

分析:引入偏向锁是为了在无多线程竞争的情况下尽量减少不必要的轻量级锁执行,因为轻量级锁的释放和获取依赖多次的CAS操作,而偏向锁只需要在置换线程ID的时候依赖一次CAS(由于一旦出现多线程竞争的情况就必须撤销偏向锁,所以偏向锁的撤销操作的性能损耗必须小于节省下来的CAS消耗),轻量级锁是为了在线程交替执行同步块时提高性能,而偏向锁则是在只有一个线程执行同步块时提高性能!

偏向锁加锁过程:

偏向锁加锁发生在偏向线程第一次进入同步块的时候,CAS操作尝试更新对象的Mrak Word(锁标志位为1,记录偏向线程的ID)

撤销偏向锁等待过程:

当有另外一共线程来竞争锁时,就需要将偏向锁膨胀为重量级,竞争线程尝试CAS更新Mark Work失败,会等到安全局点(此时不会执行任何代码)撤销偏向锁

Java线程安全与锁优化的更多相关文章

  1. Java线程安全与锁优化,锁消除,锁粗化,锁升级

    线程安全的定义 来自<Java高并发实战>"当多个线程访问一个对象的时候,如果不用考虑这些线程在运行时环境下的调度和交替执行,也不需要进行额外的同步,或者在调用方法的时候进行任何 ...

  2. Java虚拟机--线程安全和锁优化

    Java虚拟机--线程安全和锁优化 线程安全 线程安全:当多线程访问一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替执行,也不需要额外的同步,或者在调用方进行任何其他的协调操作,调用这个对象 ...

  3. 深入理解java虚拟机-第13章-线程安全与锁优化

    第十三章 线程安全与锁优化 线程安全 java语言中的线程安全 1 不可变.Immutable 的对象一定是线程安全的 2 绝对线程安全 一个类要达到不管运行时环境如何,调用者都不需要额外的同步措施, ...

  4. 《深入理解Java虚拟机》-----第13章 线程安全与锁优化

    概述 在软件业发展的初期,程序编写都是以算法为核心的,程序员会把数据和过程分别作为独立的部分来考虑,数据代表问题空间中的客体,程序代码则用于处理这些数据,这种思维方式直接站在计算机的角度去抽象问题和解 ...

  5. JVM之java并发 ——线程安全与锁优化

    概述 人们很难想象现实中的对象在一项工作进行期间,会被不停地中断和切换,对象的属性(数据)可能会在中断期间被修改和变“脏”,而这些事情在计算机世界中则是很正常的事情.有时候,良好的设计原则不得不向现实 ...

  6. 深入理解Java虚拟机(第三版)-14. 线程安全与锁优化

    14. 线程安全与锁优化 1. 什么是线程安全? 当多个线程同时访问一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替进行,也不需要进行额外的同步,或者在调用方进行任何其他的协调操作,调用这个 ...

  7. 《深入了解java虚拟机》高效并发读书笔记——Java内存模型,线程,线程安全 与锁优化

    <深入了解java虚拟机>高效并发读书笔记--Java内存模型,线程,线程安全 与锁优化 本文主要参考<深入了解java虚拟机>高效并发章节 关于锁升级,偏向锁,轻量级锁参考& ...

  8. JVM-并发-线程安全与锁优化

    线程安全与锁优化 1.线程安全 (1)当多个线程访问一个对象时,如果不考虑这些线程在执行时环境下的调度和交替执行,也不需要进行额外的同步,或者在调用方进行任何其他的协调操作,调用这个对象的行为都可以获 ...

  9. jvm(13)-线程安全与锁优化(转)

    0.1)本文部分文字转自“深入理解jvm”, 旨在学习 线程安全与锁优化 的基础知识: 0.2)本文知识对于理解 java并发编程非常有用,个人觉得,所以我总结的很详细: [1]概述 [2]线程安全 ...

随机推荐

  1. 如何用ABP框架快速完成项目(7) - 用ABP一个人快速完成项目(3) - 通过微服务模式而不是盖楼式来避免难度升级和奥卡姆剃刀原理

    这节文章十分重要!十分重要!十分重要!   很多同学在使用ABP的过程中遇到很多问题, 花费了很多时间和精力都还无法解决, 就是卡在这节文章这里.   Talk is cheap, just show ...

  2. Wyn BI的机会在哪里:越靠近消费者的行业,比如零售、文娱和金融,信息化投入越大 ZT

    近日,全球知名信息技术咨询公司IDC在网易云创大会上发布了<2018中国企业数字化发展报告>(下称报告).报告显示,近几年我国数字经济占GDP比重逐年增加,至2017年已经达到32.9%, ...

  3. Android SharedPreferences增,删,查操作

    SharedPreferences是Android平台上一个轻量级的存储类,用来保存应用的一些常用配置,比如Activity状态,Activity暂停时,将此activity的状态保存到SharedP ...

  4. Android为TV端助力 转载:android MVC设计模式

    Controller控制器 import android.app.Dialog; import android.app.ProgressDialog; import android.os.Bundle ...

  5. [翻译]SQL Server等待事件—THREADPOOL

      前言: 本文是对SQLSkills上一篇关于SQL Server中THREADPOOL等待的博客的翻译,本文也不是完全翻译,有些地方适当加入了自己的一些认知.如有翻译不对或不好的地方,敬请指出,大 ...

  6. create table 使用select查询语句创建表的方法分享

    转自:http://www.maomao365.com/?p=6642 摘要:下文讲述使用select查询语句建立新的数据表的方法分享 ---1 mysql create table `新数据表名` ...

  7. Fatal error: Can't open and lock privilege tables: Table 'mysql.host' doesn't exist

    今天在用一键安装mysql的shell脚本安装mysql-5.1.73软件后发现mysql始终无法启动,多次执行后依旧报错,只能去查看error日志,发现了如下的2个错误: 错误一:Fatal err ...

  8. Windows四大傻X功能——那些拖慢系统性能的罪魁祸首

    最近新装了一个PC,配置还算蛮高,i7的CPU,8G内存,2T的硬盘,于是小心翼翼地装了一个干净的正版Win7,但是发现居然开机明显卡?所以做了些研究,发现即使全新安装的正版windows,居然也有些 ...

  9. python3+正则表达式爬取 猫眼电影

    '''Request+正则表达式抓取猫眼电影TOP100内容''' import requests from requests.exceptions import RequestException i ...

  10. C# -- 交错数组的使用

    C# -- 交错数组的使用 交错数组是元素为数组的数组.交错数组元素的维度和大小可以不同.交错数组有时称为“数组的数组”. 1. 举例一:子数组是长度相同的一维数组 static void Main( ...