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. Javascirpt 常见的误区

    var foo = new Object(); var bar = new Object(); var map = new Object(); map[foo] = "foo"; ...

  2. 学习python5面向

    类有一个名为 __init__() 的特殊方法(构造方法),该方法在类实例化时会自动调用 面向过程:根据业务逻辑从上到下写代码 面向对象:将数据与函数绑定到一起,进行封装,这样能够更快速的开发程序,减 ...

  3. Android-ContentProvider理解操作系统的多媒体

    在多年以前,我做一款音乐播放器,要把很多.mp3文件,放置在自己新建的文件夹里面,然后去读取这个新建的文件夹里面的音乐列表,现在想想是多么的无知: 因为只要往手机里面放入.mp3文件,系统会自动检测, ...

  4. where语句中多条件查询字段NULL与NOT NULL不确定性查询

    SELECT * FROM Table where a.TenantKey=@TenantId AND (@ProjectKeys is null or b.RecuritProjectKey in ...

  5. thinkphp里数据嵌套循环

    做thinkphp时要用到循环里面嵌套循环的,并第二个循环是和外面的有关联的. thinkphp官网给出的文档为: <volist name="list" id=" ...

  6. onbeforeunload事件

    window.onbeforeunload=function(){ return "您正在编辑的博客尚未保存,确定要离开此页吗?"; }; 1.这个事件存在的意义就是防止用户不小心 ...

  7. jsonp的使用记录

    最近前端的同事说要写一个手机查看的html5页面,需要我提供数据. 这个很ok啊,立马写了个服务返回数据.但是对方调用不了,因为跨域了. 返回错误如下:  Failed to load xxxxxx: ...

  8. Linq to SQL 中将数字转换为字符串

    使用LINQ to Entities中的SqlFunctions调用数据库中的函数 添加引用System.Data.Entity 引用命名空间 using System.Data.Objects.Sq ...

  9. WPF 控件库——仿制Windows10的进度条

    WPF 控件库系列博文地址: WPF 控件库——仿制Chrome的ColorPicker WPF 控件库——仿制Windows10的进度条 WPF 控件库——轮播控件 WPF 控件库——带有惯性的Sc ...

  10. 快速搭建windows服务器的可视化运维环境

    开发好的程序部署在服务器上,如何对服务器的基本指标进行监控呢?最近对一套工具进行了研究,可以快速搭建服务器监管环境,很是强大,最重要的是它还很酷炫. 原理:数据采集+时序数据库+可视化,下面记录一下搭 ...