java 线程安全 synchronized 与 volatile 关键字笔记

  1. synchronized 关键字:
    1. 原理是将方法的执行对象 this对该方法对折方法下的代码块或者是静态方法上锁,只有获得锁的线程才能执行,其他的线程会进入到队列中进行等待,锁保证了并发的安全,可以顺序执行,但效率很低,甚至有bug,懒汉模式的双重检查锁的实现就是对象创建时间久了导致获取到的是一个未初始化完毕的对象,因此可以配合 volatile关键字保证变量的安全。
    2. 1.6之后优化了 synchronized 的实现,逐步递增 无锁 => 偏量锁(线程中加入调用id) => 轻量级锁(乐观锁) => 重量级锁(原来的实现)。
    3. 加在非静态方法上,锁的是整个对象的同步方法,锁的是这个对象本身。
    4. 加在静态方法上,锁的是整个类资源,锁的是类本身,而不影响创建的对象。
    5. 加在代码块上,锁的是代码块里的对象本身的同步资源,方法里其他未在同步代码块里的代码资源不会被锁。
    6. synchronized 是悲观锁,具有独占性。
    7. synchronized 锁的是资源,而类锁和对象锁的资源是两种不同的资源,因此锁在静态方法和锁在非静态方法上是互不影响的。
    8. 锁的力度要尽可能的细一点。
    9. 如果是对象引用的方式调用同步的静态方法,也会被锁,因为锁的是资源,静态方法属于类层面的资源。
  2. volatile 关键字:
    1. 不同的线程操作同一个属性时,获取到的属性并非主内存中的该属性的引用,而是获取了一个备份置于缓存中,当修改时也是修改的备份,当线程执行完毕时再将主内存中的该属性修改。volatile 关键字是在硬件层面实现了线程间的可见性。当属性有volatile关键字后,属性于缓存中的备份被修改后将立即同步至主内存中,并且会触发主线的主线嗅探机智(基于缓存一致性协议),此时缓存中的属性备份则会失效,下次查询时会从主存中重新获取,保证了属性在线程间的可见性。
    2. java的内存屏障也定义了一系列的禁止重排序的规则,使用 volatile 可以避免代码的重排序。
  3. 缓存一致性协议:
    1. 最出名的就是Intel 的MESI协议,MESI协议保证了每个缓存中使用的共享变量的副本是一致的。
      1. 它核心的思想是:当CPU写数据时,如果发现操作的变量是共享变量,即在其他CPU中也存在该变量的副本,会发出信号通知其他CPU将该变量的缓存行置为无效状态,因此当其他CPU需要读取这个变量时,发现自己缓存中缓存该变量的缓存行是无效的,那么它就会从内存重新读取。
  4. Java虚拟机规范中定义了Java内存模型(Java Memory Model,JMM),用于屏蔽掉各种硬件和操作系统的内存访问差异,以实现让Java程序在各种平台下都能达到一致的并发效果。
    1. JMM规范了Java虚拟机与计算机内存是如何协同工作的:规定了一个线程如何和何时可以看到由其他线程修改过后的共享变量的值,以及在必须时如何同步的访问共享变量。
    2. java代码在单线程时会根据代码间的依赖关系防止cpu对代码进行重排序,但是并未处理多线程的状况。
    3. 所谓的内存屏障也是为了防止单线程情况下代码的重排序,加了 volatile 关键字可以防止重排序。
    4. 常说的JVM内存模式指的是JVM的内存分区;而Java内存模型是一种虚拟机规范。
  5.  # 留言:老婆做了一个小红书账号,全是瓷砖方面的干货,大佬们如果有需求或者有兴趣可以移步了解一下,嘻嘻~

    小红书地址 GO GO GO ! ! !

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值