java内存模型(jMM)(二)
volatile关键字
volatile是一个类型修饰符(type specifier),就像大家更熟悉的const一样,它是被设计用来修饰被不同线程访问和修改的变量。volatile的作用是作为指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值。
特点:
- 其他线程对变量的修改可以立即反应到当前线程中
- 确保当前线程对volatile变量的修改,能即时的写到共享内存中,并被其他线程所见
- 使用volatile修饰的变量,编译器会保证其有序性
正确使用volatile变量的条件:
- 对变量的写操作不依赖于当前值
- 该变量没有包含在具有其他变量的表达式中
第一个条件显示volatile变量不适合用作线程安全计数器,因为在多线程中,增量操作(count++)虽然看上去是一个单独的操作,但实际上是由读取-->修改-->写入操作组成的组合操作,volatile并不能保证整个过程都是原子操作。
适用场景:
状态标志
这种类型的状态标记的一个公共特性是:通常只有一种标记状态的来回转换,而且状态变量通常是原子变量
- 一次性安全发布
缺乏同步会导致无法实现可见性,这使得确定何时写入对象引用而不是原语值变得更加困难,此时我们可以利用volatile实现对象的安全发布。这种模式的一个必要条件是:被发布的对象必须是线程安全的,或者是有效的不可变对象(有效不可变意味着对象的状态在发布后不会被修改)。volatile类型的引用可以确保对象的发布形式的可见性,但是如果对象的状态在发布后发生改变,那么需要额外的同步
- 独立观察
安全使用volatile的另一种简单模式是:定期“发布”观察结果供程序内部使用。使用该模式的另一种应用程序是收集程序的统计信息,例如记录一个程序中最后登录的用户,可以将反复使用lastUser引用来发布值,以便程序的其他部分使用。这个模式要求被发布的值是有效不可变的--即值的状态在发布后不会改变。
- “volatile bean”模式
volatile bean 模式适用于将 JavaBeans 作为“荣誉结构”使用的框架。在 volatile bean 模式中,JavaBean 被用作一组具有 getter 和/或 setter 方法 的独立属性的容器。volatile bean 模式的基本原理是:很多框架为易变数据的持有者(例如 HttpSession
)提供了容器,但是放入这些容器中的对象必须是线程安全的。
在 volatile bean 模式中,JavaBean 的所有数据成员都是 volatile 类型的,并且 getter 和 setter 方法必须非常普通 —— 除了获取或设置相应的属性外,不能包含任何逻辑。此外,对于对象引用的数据成员,引用的对象必须是有效不可变的。(这将禁止具有数组值的属性,因为当数组引用被声明为 volatile
时,只有引用而不是数组本身具有 volatile 语义)。对于任何 volatile 变量,不变式或约束都不能包含 JavaBean 属性。
- 开销较低的读-写锁策略
当读操作远远超过写操作时,我们可以结合使用内部锁和volatile变量来减少公共代码路径的开销。如果更新不频繁的话,该方法可以实现更好的性能,因为读路径的开销仅仅涉及到volatile的读操作,这通常要由于一个无竞争的锁的开销。
public class ChessyCounter{
private volatile int count;
public int getValue(){return this.count;}
public synchronized int increment(){
return count++;
}
}
之所以将这种技术称之为“开销较低的读-写锁”,是因为使用的不同的同步机制进行读写操作。由于在读操作中使用volatile可以确保当前值的可见性,所以可以使用锁进行所有变化的操作,使用volatile进行只读操作。
总结:
与锁相比,Volatile 变量是一种非常简单但同时又非常脆弱的同步机制,它在某些情况下将提供优于锁的性能和伸缩性。如果严格遵循 volatile 的使用条件 —— 即变量真正独立于其他变量和自己以前的值 —— 在某些情况下可以使用 volatile
代替 synchronized
来简化代码。然而,使用 volatile
的代码往往比使用锁的代码更加容易出错。本文介绍的模式涵盖了可以使用 volatile
代替 synchronized
的最常见的一些用例。遵循这些模式(注意使用时不要超过各自的限制)可以帮助您安全地实现大多数用例,使用 volatile 变量获得更佳性能。
synchronized关键字
synchronized 关键字,代表这个方法加锁,相当于不管哪一个线程(例如线程A),运行到这个方法时,都要检查有没有其它线程B(或者C、 D等)正在用这个方法(或者该类的其他同步方法),有的话要等正在使用synchronized方法的线程B(或者C 、D)运行完这个方法后再运行此线程A,没有的话,锁定调用者,然后直接运行。它包括两种用法:synchronized 方法和 synchronized 块。
特点:
- 被synchronized修饰的方法或代码块同一时间只能被一个线程使用
- 当一个线程访问Object的一个synchronized代码块时,另一个线程仍可访问该对象的非synchronized代码块
- 当一个线程访问Object的一个synchronized代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。
- 当一个线程访问Object的一个synchronized(this)同步代码块时,它就获得了这个Object的对象锁。结果,其他线程对该Object对象所有的同步代码部分的访问都暂时被阻塞
使用场景:
- synchronized方法:
通过在方法声明中加入synchronized关键字,synchronized 方法控制对类成员变量的访问:每个类实例对应一把锁,每个 synchronized 方法都必须获得调用该方法的类实例的锁方能执行,否则所属线程阻塞,方法一旦执行,就独占该锁,直到从该方法返回时才将锁释放,此后被阻塞的线程方能获得该锁,重新进入可执行状态。这种机制确保了同一时刻对于每一个类实例,其所有声明为 synchronized 的成员函数中至多只有一个处于可执行状态(因为至多只有一个能够获得该类实例对应的锁),从而有效避免了类成员变量的访问冲突(只要所有可能访问类成员变量的方法均被声明为 synchronized)
- synchronized代码块:
通过 synchronized关键字来声明synchronized 块,其中的代码必须获得对象 syncObject (如前所述,可以是类实例或类)的锁方能执行,具体机制同前所述。由于可以针对任意代码块,且可任意指定上锁的对象,故灵活性较高。
- synchronized方法和synchronized同步代码块的区别:
- synchronized同步代码块只是锁定了该代码块,代码块外面的代码还是可以被访问的。
- synchronized方法是粗粒度的并发控制,某一个时刻只能有一个线程执行该synchronized方法。
- synchronized同步代码块是细粒度的并发控制,只会将块中的代码同步,代码块之外的代码可以被其他线程同时访问。
final关键字
特点:
- final类不能被继承,没有子类,final类中的方法默认是final的。
- final方法不能被子类的方法覆盖,但可以被继承。
- final成员变量表示常量,只能被赋值一次,赋值后值不再改变。
- final不能用于修饰构造方法。
使用场景:
- 修饰变量
当final修饰一个变量的时候一般把他作为常量,通常和static关键字配合使用。一般static修饰的常量都用大写字母来表示。
- 修饰方法
当一个方法被final修饰后,表示该方法不能被子类重写,final方法有一个好处是比非final方法要快,因为在编译时已经静态绑定了,不需要在运行时在动态绑定。
- 修饰类
当一个类被final修饰后,表示该类是完整的,不能被继承,例如Java中String、Integer类都是final类
优点:
- final关键字提高了性能。JVM和Java应用都会缓存final变量
- final变量可以安全的在多线程环境下进行共享,而不需要额外的同步开销
- 使用final关键字,JVM会对方法、变量及类进行优化
- 不可变类创建不可变类要使用final关键字。不可变类是指它的对象一旦被创建了就不能被更改了。String是不可变类的代表。不可变类有很多好处,譬如它们的对象是只读的,可以在多线程环境下安全的共享,不用额外的同步开销等等
参考资料:
java内存模型(jMM)(二)的更多相关文章
- Java内存模型JMM与可见性
Java内存模型JMM与可见性 标签(空格分隔): java 1 何为JMM JMM:通俗地讲,就是描述Java中各种变量(线程共享变量)的访问规则,以及在JVM中将变量存储到内存和从内存中读取变量这 ...
- 多线程并发之java内存模型JMM
多线程概念的引入是人类又一次有效压寨计算机的体现,而且这也是非常有必要的,因为一般运算过程中涉及到数据的读取,例如从磁盘.其他系统.数据库等,CPU的运算速度与数据读取速度有一个严重的不平衡,期间如果 ...
- 全面理解Java内存模型(JMM)及volatile关键字(转载)
关联文章: 深入理解Java类型信息(Class对象)与反射机制 深入理解Java枚举类型(enum) 深入理解Java注解类型(@Annotation) 深入理解Java类加载器(ClassLoad ...
- 全面理解Java内存模型(JMM)及volatile关键字(转)
原文地址:全面理解Java内存模型(JMM)及volatile关键字 关联文章: 深入理解Java类型信息(Class对象)与反射机制 深入理解Java枚举类型(enum) 深入理解Java注解类型( ...
- 对多线程java内存模型JMM
多线程概念的引入体现了人类重新有效压力寨计算机.这是非常有必要的,由于所涉及的读数据的过程中的一般操作,如从磁盘.其他系统.数据库等,CPU计算速度和数据读取速度已经严重失衡.假设印刷过程中一个线程将 ...
- Java并发编程:Java内存模型JMM
简介 Java内存模型英文叫做(Java Memory Model),简称为JMM.Java虚拟机规范试图定义一种Java内存模型来屏蔽掉各种硬件和系统的内存访问差异,实现平台无关性. CPU和缓存一 ...
- Java内存模型JMM 高并发原子性可见性有序性简介 多线程中篇(十)
JVM运行时内存结构回顾 在JVM相关的介绍中,有说到JAVA运行时的内存结构,简单回顾下 整体结构如下图所示,大致分为五大块 而对于方法区中的数据,是属于所有线程共享的数据结构 而对于虚拟机栈中数据 ...
- java内存模型(二)深入理解java内存模型的系列好文
深入理解java内存模型(一)--基础 深入理解java内存模型(二)--重排序 深入理解java内存模型(三)--顺序一致性 深入理解java内存模型(四)--volatile 深入理解java内存 ...
- 什么是Java内存模型(JMM)
什么是java内存模型 缓存一致性问题 在现代计算机中,因为CPU的运算速度远大于内存的读写速度,因此为了不让CPU在计算的时候因为实时读取内存数据而影响运算速度,CPU会加入一层缓存,在运算之前缓存 ...
- 深入理解Java内存模型JMM与volatile关键字
深入理解Java内存模型JMM与volatile关键字 多核并发缓存架构 Java内存模型 Java线程内存模型跟CPU缓存模型类似,是基于CPU缓存模型来建立的,Java线程内存模型是标准化的,屏蔽 ...
随机推荐
- php static 变量声明
<?phpfunction test($key){ static $array = array(); /* 静态变量是只存在于函数作用域中的变量,注释:执行后这种变量不会丢失(下次调用这个函数 ...
- jquery设置select选中的文本
<select id="prov"> <option value="1">北京市</option> <option ...
- Python2.7.9 编码问题
最近学一学网络爬虫,遇到第一件头疼的事情就是编码问题, 看了很多教程讲得不清楚, 现在整理一下,希望以后查看方便一些 使用 sys.getdefaultencoding() 查看Python的 ...
- eclipse netbeans 代码模板
eclipse 代码模板 插入slf4j ${:import(org.slf4j.Logger,org.slf4j.LoggerFactory)} private static final Log ...
- 在windows上编译wireshark源代码
终于在windows上成功编译了wireshark源代码,个中酸辛,都是泪..只能说要多试! windows上编译wireshark共用到三个东西:wireshark源代码.python.cygwin ...
- C primer 编程练习 (不断更新)
目前在看<C Primer>,以后会经常在这篇博客里更新课后的编程练习题 第二章:编程练习 2.1 #include <stdio.h> int main(void) { pr ...
- 浅谈https\ssl\数字证书
全球可信的SSL数字证书申请:http://www.shuzizhengshu.com 在互联网安全通信方式上,目前用的最多的就是https配合ssl和数字证书来保证传输和认证安全了.本文追本溯源围绕 ...
- 自己(转)String、StringBuffer与StringBuilder之间区别
String.StringBuffer与StringBuilder之间区别 最近学习到StringBuffer,心中有好些疑问,搜索了一些关于String,StringBuffer,StringB ...
- SpringCloud教程 | 第六篇: 分布式配置中心(Spring Cloud Config)(Finchley版本)
在上一篇文章讲述zuul的时候,已经提到过,使用配置服务来保存各个服务的配置文件.它就是Spring Cloud Config. 一.简介 在分布式系统中,由于服务数量巨多,为了方便服务配置文件统一管 ...
- 第一课 了解SQL
1.1数据库基础 数据库:数据库是一个以某种有组织的方式存储的数据集合,可以想象是一个文件柜 数据库管理软件:DBMS用来操做创建数据库的软件 表:某种特定类型数据的结构化清单,数据库的下一层就是表 ...