Java多线程之内存可见性和原子性:Synchronized和Volatile的比较 【尊重原创,转载请注明出处】http://blog.csdn.net/guyuealian/article/...类似"a += b"这样的操作不具有原子性,在某些JVM中"a += b"可能要经过这样三个步骤: ① 取出a和b ② 计算a+b ③ 将计算结果写入内存 (1)Synchronized:保证可见性和原子性...Synchronized能够实现原子性和可见性;在Java内存模型中,synchronized规定,线程在加锁时,先清空工作内存→在主内存中拷贝最新变量的副本到工作内存→执行完代码→将更改后的共享变量的值刷新到主内存中...(2)Volatile:保证可见性,但不保证操作的原子性 Volatile实现内存可见性是通过store和load指令完成的;也就是对volatile变量执行写操作时,会在写操作后加入一条store...(3)Synchronized和Volatile的比较 1)Synchronized保证内存可见性和操作的原子性 2)Volatile只能保证内存可见性 3)Volatile不需要加锁
早在单核时代,使用锁或者原子变量就很容易达成这一目的。甚至因为CPU的一些访存特性,对某些内存对齐数据的读或写也具有原子的特性。...也就是说,有些内存对齐的数据的访问在CPU层面就是原子进行的(注意这里说的只是单次的读或者写,类似普通变量i的i++操作不止一次内存访问)。...原因就是read_index和writer_index的写操作在满足对齐内存访问的情况下是原子的,不需要额外的同步措施。...注意这里我加粗了单核CPU这个关键字,那么到了多核心处理器的今天,该操作就不是原子了吗?不,依旧是原子的,但是出现了其他的干扰因素迫使可能需要额外的同步措施才能保证原本无锁代码的正确运行。...虽然说一般情况下程序员只需要关注顺序一致性即可,但是区分清楚这两个概念也能更好的解释内存屏障(Memory Barrier)。
不同,C/C++中的volatile不提供任何防止乱序的功能,也并不保证访存的原子性。...另外, 除了显式的内存屏障指令,有些指令也会造成指令保序的效果,比如I/O操作的指令、exch等原子交换的指令,任何带有lock前缀的指令以及CPUID等指令都有内存屏障的作用。...与之类似,平台提供的原子变量除了保证内存操作原子之外,也会保证访存的一致性。...GCC提供了Built-in的原子操作函数可以使用,GCC 4以后的版本也提供了Built-in的屏障函数__sync_synchronize(),这个屏障函数既是编译屏障又是内存屏障,代码插入这个函数的地方会被安插一条...至于工程上,普通的程序员老老实实的用Mutex就好了,普通的计数类场景用原子变量也无可厚非。
而对于程序员而言,如何避免内存泄漏也是一门学问,倘若不加以控制,那么无论多大的内存都会有消耗殆尽的那天。...本文当然不是研究如何分析内存泄漏的产生原因与解决方案,而是在此之前的一步,通过简单的内存监测方式来预测内存泄漏的 潜在可能性 或者 偶发性 等。...我这边需要监测 系统内存 与 jvm堆内存 ,最终的结果会展示各个时间点的内存情况,所以需要一个时间类,表示每个切片的时间点。...timeMarkInterval是存储定时器id的,在销毁之前释放定时器;physicMemory和heapMemory获取图表div节点,用于echarts节点获取;systemInfo则会存储定时从服务器拉取到的数据...由图可见我这个系统堆内存通常消耗不到一百兆,后续可以将堆内存设定的再小一些,以提供给其它服务使用。总体内存是稳定状态,达到一定值会自动回收垃圾,占用率不会逐步提高,是个可控的系统。
早上到单位 发现服务器 mysql 服务器停了 然后起来了 查询日志 显示 内存满了 把mysql服务给杀了 linux 服务器如果 内存满了 会自动清理进程 防止服务器挂掉 选择的话 谁占的的内存大...就先杀谁 我的服务器里面 mysql服务占的内存是最大的 所以就把mysql就给杀了 image.png 然后 重启mysql 查询内存 image.png 在这说一下 怎么看linux的内存 举个例子...空闲的内存数: 232M shared 当前已经废弃不用,总是0 buffers Buffer 缓存内存数: 62M cached Page 缓存内存数:421M 关系:total(1002M) = used...记住内存是拿来用的,不是拿来看的.不象windows, 无论你的真实物理内存有多少,他都要拿硬盘交换文件来读.这也就是windows为什么常常提示虚拟空间不足的原因.你们想想,多无聊,在内存还有大部分的时候...,拿出一部分硬盘空间来充当内存.硬盘怎么会快过内存.所以我们看linux,只要不用swap的交换空间,就不用担心自己的内存太少.如果常常 swap用很多,可能你就要考虑加物理内存了.这也是linux看内存是否够用的标准哦
从Java内存模型的角度来看,简单的counter++的执行过程其实分为如下三步: 从主内存中加载counter的值到线程工作内存 执行加1运算 把第二步的执行结果从工作内存写入到主内存 那么现在假设主内存中...从上面这个引起错误的流程可以看出,之所以结果错误,其本质是两个线程同时操作了同一块内存,线程1执行++运算的过程中插入了线程2的++操作,也就是说从另外一个线程的角度看++操作并不是一个原子操作。...高版本的gcc提供了一系列原子操作函数,比如__sync_fetch_and_add函数实现了原子的从内存中读取一个值,然后执行加法操作,最后把结果写入内存。...:首先从内存中读取a的值,然后求和并把求和结果存入变量a之中,即: 从内存读取变量a的值到寄存器 与2相加 把相加后的结果存入变量a对应的内存 这明明是三步操作为什么能够保证原子操作呢,答案就在于xadd...这个指令,cpu执行这个指令之前首先会把这条指令之前的读写内存操作完成,然后锁住内存总线直到执行完上面的三步操作之后才释放总线,在这段时间之内,其它cpu是无法访问内存的,这就保证了加法操作的原子性(另外
原子操作 原子操作类型 原子操作是指一个或者多个不可再分割的操作。这些操作的执行顺序不能被打乱,这些步骤也不可以被切割而只执行其中的一部分(不可中断性)。...在 Java 中通过原子操作来完成工作内存和主内存的交互,其中原子操作又可分为如下几类: 操作 作用目标 功能 lock 主内存 把变量标识为线程独占状态 unlock 主内存 解除独占状态 read...主内存 把一个变量的值从主内存传输到线程的工作内存 load 工作内存 把 read 操作传过来的变量值放入工作内存的变量副本中 use 工作内存 把工作内存当中的一个变量值传给执行引擎 assign...工作内存 把一个从执行引擎接收到的值赋值给工作内存的变量 store 工作内存中的变量 把工作内存的一个变量的值传送到主内存中 write 主内存中的变量 把 store 操作传来的变量的值放入主内存的变量中...也因为 volatile 要求三个连续的操作,所以禁用了指令重排序,但同时也失去了原子性的特点(即单一的原子操作)。 而 volatile 关键字通过“内存屏障”来防止指令被重排序。
第5章 C++内存模型和原子操作 5.1 内存模型基础 C++标准中对象定义为某一存储范围。...若两个线程访问同一内存区域并且没有强制服从一定的次序,当其中有非原子化访问以及写操作时,就会出现数据竞争,导致未定义行为。...对于原子类型上的每种操作,都可以提供额外参数,用于设定内存次序语义,具体见5.3节。...同步关系指对某变量执行原子写和原子读,且两者都有适当的标记。先行关系在单线程中指源代码中操作语句的先后,多线程中先行关系可通过同步关系传递。 原子类型上的操作服从6种内存次序。...下面的例子中两个内存屏障原子操作atomic_thread_fence之间同步,使得x先存储true再读取,最后的断言不会报错。
认识 Atomic 原子类 Atomic 翻译成中文是原子的意思。在化学中,原子是构成一般物质的最小单位,是不可分割的。...JUC 原子类概览 JUC 包中的原子类 基本类型 使用原子的方式更新基本类型 AtomicInteger:整形原子类 AtomicLong:长整型原子类 AtomicBoolean:布尔型原子类 数组类型...使用原子的方式更新数组里的某个元素 AtomicIntegerArray:整形数组原子类 AtomicLongArray:长整形数组原子类 AtomicReferenceArray:引用类型数组原子类...引用类型 AtomicReference:引用类型原子类 AtomicStampedReference:原子更新引用类型里的字段原子类 AtomicMarkableReference :原子更新带有标记位的引用类型...UnSafe 类的 objectFieldOffset() 方法是个本地方法,这个方法是用来拿“原值”的内存地址,返回值是 valueOffset;另外,value 是一个 volatile 变量,因此
也就是上面的原子类实现过程中都会用到Unsafe类。Java中的Unsafe类提供了类似C++手动管理内存的能力。...Unsafe的典型应用 堆外内存操作。...DirectByteBuffer是Java用于实现堆外内存的一个重要类,通常用在通信过程中做缓冲池,如在Netty、MINA等NIO框架中应用广泛;DirectByteBuffer对于堆外内存的创建、...使用、销毁等逻辑均由Unsafe提供的堆外内存API来实现; ReentrantLock、Atomic等API通过CAS修改state等等,底层用的也是Unsafe; 线程调度:如LockSupport.park...而 LockSupport的park、unpark方法实际是调用Unsafe的park、unpark方式来实现; 内存屏障,通过Unsafe的loadFence方法加入一个内存屏障,目的是避免指令重排。
原子操作类 原子性这个概念,在多线程编程里是一个老生常谈的问题。 所谓的原子性表示一个或者多个操作,要么全部执行完, 要么一个也不执行。不能出现成功一部分失败一部分的情 况。...因为 A 和 B 在更新变量 i 的时候拿到的 i 可能都是 1 这就是一个典型的原子性问题。 多线程里面,要实现原子性,有几 种方法,其中一种就是加 Synchronized 同步锁。...J.U.C 中的原子操作类 由于变量类型的关系,在 J.U.C 中提供了 12 个原子操作的 类。这 12 个类可以分为四大类。 1....(loadFence/storeFence) 内存管理(内存分配、释放内存、获取内存地址等.) public final int getAndIncrement() { return unsafe.getAndAddInt...通过 unsafe.objectFieldOffset() 获取当前 Value 这个变量在内存中的偏移量,后续会基于 这个偏移量从内存中得到value的值来和当前的值做比较, 实现乐观锁 private
1.认识原子操作 原子操作就是在多线程程序中“最小的且不可并行化的”操作,意味着多个线程访问同一个资源时,有且仅有一个线程能对资源进行操作。...C++11通过引入原子类型帮助开发者轻松实现原子操作。...使用C++11提供的原子类型与多线程标准接口,简洁地实现了多线程对临界资源的原子操作。...,原子类型能够实现原子操作是因为C++11对原子类型的操作进行了抽象,定义了统一的接口,并要求编译器产生平台相关的原子操作的具体实现。...---- 参考文献 [1]《深入理解C++11》笔记-原子类型和原子操作 [2]深入理解C++11[M].6.3原子类型与原子操作.P196-P214
在深入了解服务器 CPU 的型号、代际、片内与片间互联架构一文中我们了解了服务器 CPU 的内部架构。在其中我们看到有一个内存控制器。 关于CPU内存控制器中会有很多专技术细节。...而且不再像之前一样要求每个内存颗粒传输距离相等,工艺复杂度因寄存缓存器的引入而下降,使得容量也可以提高到 32 GB。主要用在服务器上。 下图是一个服务器RDIMM 32 GB 内存条。...这个服务器内存条不光正面有很多内存颗粒,连背面也有。可见服务器内存的颗粒数量比普通笔记本电脑、个人台式机的颗粒都要多很多。...另外一台服务器经常是连续要运行几个月甚至是几年。因此总的来说,服务器对稳定性的要求极高,不允许比特翻转错误发生。 ECC 是一种内存专用的技术。...服务器 CPU 支持 RDIMM(带寄存器双列直插模块)和 LRDIMM(低负载双列直插内存模块)内存。这两种内存单条都有更大的容量。
Typecho博客系统显示服务器占用内存的插件,代码很简单,这插件作者是12年写的,我用了已经不能用,我通过自学的一丢丢的PHP基础,简单的整理了一下,又能用了,奇怪的知识又涨了 插件截图 调用代码
0,线程1加1并写入主内存,现在主内存变量值1,线程2也加2并尝试写入主内存,这个时候是不能写入主内存的,因为会覆盖掉线程1的操作,具体过程如下图。...CAS是在线程2尝试写入内存的时候,通过比较并设置(CompareAndSet)发现现在主内存当前值为1,和他刚开始读取的值0不一样,所以他会放弃本次修改,重新读取主内存的最新值,然后再重试下线程2的具体逻辑操作...,再次尝试写入主内存。...如果这时候线程1,再次对主内存进行了修改,线程2发现现在主内存的值又和预期不一样,所以将放弃本次修改,再次读取主内存最新值,再次重试并尝试写入主内存。...原子引用 在日常使用中,我们不止对上述基本类型进行原子操作,而是需要对一些复杂类型进行原子操作,所以需要AtomicReference。
Atomic 原子类原子对象的单个方法具有原子性,通过 CAS 算法和自旋操作实现,并发效率高。使用时需导入 import java.util.concurrent.atomic.*。...}}class MyThread implements Runnable { AtomicInteger count = new AtomicInteger(0); // 定义整型地原子类...{ for (int i = 0; i < 10000; i++) { count.incrementAndGet(); // 原子性自增操作
CAS(Compare And Swap): 我们先要学习的是并发编程中的CAS,也就是原子操作 那么,什么是原子操作?如何实现原子操作?...,其他线程必须等待已经获得锁的线程运行完车之后才能获取锁,这样就会占用系统大量资源 CAS原理: 从CPU指令级别保证这是一个原子操作 CAS包含哪些参数: 三个运算符: 一个内存地址V...就是内存中原本是A,然后通过CAS变成了B,然后再次通过CAS变成了A,这个过程中,相对于结果来说,是没有任何改变的,但是相对于内存来说,至少发生过两次变化,这就是ABA问题 生活中: ...第二它可以避免在退出循环的时候因内存顺序冲突(memory order violation)而引起CPU流水线被清空(CPU pipeline flush),从而提高CPU的执行效率。 ...,但是源对象src却没有改变,因为原子引用类和原对象本身是两个东西,CAS后就可以理解为内存中的东西变了,也可以说是引用变了,他只能保证你在改变这个引用的时候保证是原子性的 记得之前上面说的ABA问题吧
领取专属 10元无门槛券
手把手带您无忧上云