volatile

特征:

a:可见性:一个线程修改了某个共享变量的值,其他线程能够立马得知这个修改。

b:禁止特定的处理器重排序。

volatile的内存语义:

1.当写一个volatile变量的时候,jmm会把本地内存中的共享变量刷新到主内存。

2.当读一个volatile变量的是时候,jmm会把线程本地内存的值设置为无效,然后从主内存中读取共享变量。

volatile的重排序有三个规则:

1.当第二个操作为volatile写的时候,第一个操作不管是什么,都不允许重排序。

2.当第一个操作为volatile读的时候,第二个操作不管是什么,都不允许重排序。

3.当第一个操作为volatile写的时候,第二个操作是volatile读的时候,不允许重排序。

除此以外的情况,都运行重排序。而重排序的实现是靠加入内存屏障来实现的。内存屏障时用来禁止特定的重排序的cpu指令。包括4中,loadload,store store,store load与load/store。load可以理解为读操作,store可以理解为写操作,举例说明,loadload是保证在第二个load和其他一系列操作之前要确保第一个load的读操作完成。store store是保证在第二个store及写操作之前,第一个store写操作对其他处理器可见。其中store load的开销最大,是个万能屏障,兼具其他三个屏障的功能。

synchronized和lock的底层实现和对比:

synchronized是通过jvm原生实现的,其中可以分为给代码块加锁,给方法加锁,给静态类加锁。给代码块加锁锁住的是加锁的对象,给方法加锁锁住的是对象实例,给静态类加锁锁住的是整个类。

jvm通过进入和退出monitor来实现代码块和方法的同步。其中给代码块加锁可以理解为在方法的入口和出口分别加入了monitorenter和monitorexit字节码指令来实现的。必须要保证有一个monitorenter对应一个monitorexit,进入到monitorenter就表示拿到了相应的锁。java1.6之前synchronized可以说是重量级锁,1.6之后对synchronized做出的优化使得synchronized没有那么重量级了,加入了锁粗化,自旋锁和自适应自旋,锁消除,轻量级锁,偏向锁。

锁粗化是对对一个代码块家了很多锁,由于要不停的进入和出去加大的开销,可以把一部分联系紧密的代码块合并为一个锁或者少量的锁,使锁的力度变粗。

锁消除是当代码块中有锁但是检测到不存在竞争没有必要加锁的时候就把锁去掉。

自旋锁:同步的时候阻塞会影响性能,挂起线程和恢复线程的操作都需要转入内核态来完成,这些操作给系统的并发性能带来的很大的压力。在很多共享数据的锁定状态之后持续很短的一段时间,为了这段时间去挂起和恢复线程并不值得。如果物理机上不止一个处理器,能让两个或以上的线程同时并行执行,我们可以让后面请求锁的线程“稍等一下”,但是不放弃cpu,看看持有锁的线程是否很快就会释放锁。为了让线程等待,我们只需让线程执行一个等待,这就是自旋。自旋值默认是10。1.6中引入了自适应的自旋,如果前一个刚刚获得过锁,并且持有锁的线程还在进行中,那么虚拟机会认为下一次自旋也有可能成功,进而允许自旋等待更长时间。对于很少获得的锁,直接放弃自旋,避免资源浪费,直接挂起线程。

轻量级锁:轻量级锁是相对于重量级锁而言的,它的本意是在没有多线程竞争的前提下,减少传统的重量级锁使用操作系统互斥量产生的性能消耗。在进入代码块的时候,如果此同步对象没有被锁定,也就是锁标志位是01状态,虚拟机首先在当前线程的栈帧上建立一个锁记录(lock record),用于存储Mark world的拷贝,然后虚拟机将使用cas操作尝试将对象的Mark world更新指向lock record的指针。更新成功了那么该线程就拥有了锁,并且对象的锁标志位将装换为00,即表示此对象处于轻量级锁的状态。更新失败了,虚拟机首先检查Mark world是否指向lock record,是的话说明当前线程已经拥有了这个对象的锁,那就直接进去代码块继续执行,否则说明锁对象已经被其他线程抢占了。如果有两个以上的对象争用一个锁,那么轻量级锁不再有效,升级为重量级锁,锁状态变为10,mark word中存储的就是重量级锁的指针。

偏向锁:如果说轻量级锁是在无竞争的条件下使用cas操作去消除同步使用的互斥量,那么偏向锁就是在无竞争的条件下把整个同步都省掉,连cas操作都不做了。偏向的偏,意思就是如果获取了锁,下一个获取的话偏向由上一次获取它的线程来获取。当线程第一次获取到锁对象,状态改写为01,然后使用cas操作,把获取到锁的线程的id记录在mark word中,如果cas成功,持有偏向锁的线程以后每次进入这个锁相关的同步块时,虚拟机都可以不在进行任何同步操作。当有另外一个线程去尝试获取这个锁时,偏向模式宣告结束。根据锁对象目前是否处于锁定的状态,撤销偏向后恢复到未锁定或轻量级锁定。

而lock是Java写的,基于aqs框架,需要显示的获取锁和释放锁,并且包含在try catch finally语句块里面,同样是可重入锁,lock还提供了比synchronized更强大的一些功能。主要包括三点:

1.可中断获取锁,获取锁的时候可以定时,如果过了这个时间还是没有获得锁,那么就改为做其他事情。

2.可以绑定多个条件。synchronized里面,如果用wait、notify的话,实现的是隐含的一个条件,如果要和多于一个的条件绑定的话需要再创建锁。而lock不需要,一个锁可以产生多个condition,只需要通过lock的newcondition方法即可。

3.可以实现公平锁。

volatile和synchronized与lock的理解的更多相关文章

  1. 线程、volatile与synchronized、Lock

    目录 线程 1.概念: 2.线程生命周期: 3.线程调度 4.线程实现 4.1.实现方式 4.2.之间的区别: 5.线程安全 5.1.volatile与synchronized 5.1.synchro ...

  2. Java并发编程知识点总结Volatile、Synchronized、Lock实现原理

    Volatile关键字及其实现原理 在多线程并发编程中,Volatile可以理解为轻量级的Synchronized,用volatile关键字声明的变量,叫做共享变量,其保证了变量的“可见性”以及“有序 ...

  3. volatile、synchronized、lock有什么区别,以及在哪些场景下使用哪种方式?

    [转]JVM锁机制volatile/synchronized/lock 1.volatile实现原理 (1)聊聊并发(一)——深入分析Volatile的实现原理 --硬件级别锁实现,Lock前缀指令会 ...

  4. 从JMM透析volatile与synchronized原理,图文并茂

    在面试.并发编程.一些开源框架中总是会遇到 volatile 与 synchronized .synchronized 如何保证并发安全?volatile 语义的内存可见性指的是什么?这其中又跟 JM ...

  5. synchronized和lock以及synchronized和volatile的区别

    synchronized和volatile区别synochronizd和volatile关键字区别: 1. volatile关键字解决的是变量在多个线程之间的可见性:而sychronized关键字解决 ...

  6. java学习:JMM(java memory model)、volatile、synchronized、AtomicXXX理解

    一.JMM(java memory model)内存模型 从网上淘来二张图: 上面这张图说的是,在多核CPU的系统中,每个核CPU自带高速缓存,然后计算机主板上也有一块内存-称为主内(即:内存条).工 ...

  7. 理解volatile与synchronized

    用 volatile 修饰的变量可以保证线程的"可见性",也就是,任何线程修改了这个 volatile 修饰的值都会通知其他线程来主缓存中重新读取值. 下面通过例子加以说明: pu ...

  8. 剑指Offer——线程同步volatile与synchronized详解

    (转)Java面试--线程同步volatile与synchronized详解 0. 前言 面试时很可能遇到这样一个问题:使用volatile修饰int型变量i,多个线程同时进行i++操作,这样可以实现 ...

  9. 详解synchronized与Lock的区别与使用

    知识点 1.线程与进程 在开始之前先把进程与线程进行区分一下,一个程序最少需要一个进程,而一个进程最少需要一个线程.关系是线程–>进程–>程序的大致组成结构.所以线程是程序执行流的最小单位 ...

随机推荐

  1. JavaEE互联网轻量级框架整合开发(书籍)阅读笔记(12):XML配置自动扫描包,自动加载*.properties文件

    一.XML和注解组合使用 前几篇的测试案例都是在Java类中配置,现在换一种使用方式,在XML中配置,使Spring IoC容器在启动之后自动去扫描配置的包路径,扫描加载指定路径下的propertie ...

  2. 设计模式17:Iterator 迭代器模式(行为型模式)

    Iterator 迭代器模式(行为型模式) 动机(Motivation) 在软件构建过程中,集合对象内部结构常常变化各异.但对于这些集合对象,我们希望在不暴露其内部结构的同时,可以让外部客户代码可以透 ...

  3. 团体程序设计天梯赛L3-010 是否完全二叉搜索树 2017-03-24 16:12 29人阅读 评论(0) 收藏

    L3-010. 是否完全二叉搜索树 时间限制 400 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 陈越 将一系列给定数字顺序插入一个初始为空的二叉搜 ...

  4. Android dex分包方案和热补丁原理

    一.分包的原因: 当一个app的功能越来越复杂,代码量越来越多,也许有一天便会突然遇到下列现象: 1. 生成的apk在2.3以前的机器无法安装,提示INSTALL_FAILED_DEXOPT 2. 方 ...

  5. CentOS下安装PHP的AMQP扩展方法和步骤

    AMQP,即Advanced Message Queuing Protocol,一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计.基于此协议的客户端 ...

  6. 只是误以为导入了maven依赖

    背景: 之前用Spring Boot 开发了一个小项目,考虑将代码迁到Git服务器,由于之前没用过Git,在将代码正式签入Git服务器前, 我想先签入一个最简单的Spring Boot程序代码作为试验 ...

  7. Windows上编译LLVM 3.2

    LLVM还是做的很好的,可以很方便的编译. 解压LLVM 3.2到[工作目录]/llvm/llvm-3.2.src 解压Clang到[工作目录]/llvm/llvm-3.2.src/tools/cla ...

  8. 【05】循序渐进学 docker:系统资源和网络

    写在前面的话 在上一篇学习 Dockerfile 的时候其实还有几个相当重要得关键中没有谈到,但没关系,在后面的内容会单独提出来一个一个的学习.这里就先谈谈关于资源的控制个容器的网络~ 资源限制 其实 ...

  9. 爬虫开发7.scrapy框架简介和基础应用

    scrapy框架简介和基础应用阅读量: 1432 scrapy 今日概要 scrapy框架介绍 环境安装 基础使用 今日详情 一.什么是Scrapy? Scrapy是一个为了爬取网站数据,提取结构性数 ...

  10. 【bzoj5084】 hashit(广义SAM+set)

    题面 传送门 题解 后缀平衡树是个啥啊我不会啊-- 那么我们来考虑一下\(SAM\)的做法好了 不难发现它的本义是要我们维护一棵\(trie\)树,并求出\(trie\)树上每一个节点到根的这段串的不 ...