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. sql 两大类 DDL数据定义语言 和DCL数据控制语言

    SQL分为五大类: DDL:数据定义语言   DCL:数据控制语言     DML:数据的操纵语言  DTL:数据事务语言  DQL:数据查询语言. DDL (date definition lang ...

  2. unittest测试框架详谈及实操(三)

    断言 unittest的TestCase类提供了很多实用的方法来校验预期结果和程序返回的实际结果是否一致.当然这些方法要求必须满足某些条件才能继续执行接下的测试.大致有3种这样的方法.各覆盖一个特定类 ...

  3. jquery插件中(function ( $, window, document, undefined )的作用

    在jquery插件中我们经常看到以下这段代码 ;(function ( $, window, document, undefined ){ //函数体内具体代码 })(jQuery, window,d ...

  4. numpy.convolve()

    卷积函数: numpy.convolve(a, v, mode='full') Parameters: a : (N,) array_like First one-dimensional input ...

  5. 深入理解java虚拟机(十) Java 虚拟机运行时栈帧结构

    运行时栈帧结构 栈帧(Stack Frame) 是用于虚拟机执行时方法调用和方法执行时的数据结构,它是虚拟栈数据区的组成元素.每一个方法从调用到方法返回都对应着一个栈帧入栈出栈的过程. 每一个栈帧在编 ...

  6. 《T-SQL查询》- SQL逻辑处理

    下面列出SQL查询语句的一般形式,以及各个子句被逻辑处理的顺序步骤: (8) SELECT (9) DISTINCT (11) <TOP_specification> <select ...

  7. mybatis--mapper配置总结

    mapper介绍 mapper使用规则:按业务划分,一个业务模块相关的sql均定义在一个mapper文件 mapper的xml格式: doctype: <!DOCTYPE mapper PUBL ...

  8. jQuery制作多表格固定表头、切换表头的特效

    做了好几天的固定表头特效,总算是搞定了.先说明一下基本功能:我们在一个网页上浏览很多份表格数据的时候,肯定会碰到很多分不清表头,也分不清表 格是哪个的情况,这个时候我们就希望能有一种功能,就是我们再下 ...

  9. android之实现底部TabHost

    先说布局文件,如下:利用android:layout_alignParentBottom="true" 实现底部显示 <?xml version="1.0" ...

  10. SqlServer:CTE函数处理递归(WITH语法)

    原文地址:http://www.cnblogs.com/xbf321/archive/2009/04/30/1446833.html 我们在做分类处理的时候,总会遇到递归的处理,比如说地区就是一个例子 ...