Java 并发之共享对象
上一篇文章说的是,避免多个线程在同一时间访问对象中的同一数据,这篇文章来详细说说共享和发布对象。
在没有同步的情况下,我们无法预料编译器、处理器安排操作执行的顺序,经常会发生以为“一定会”发生的动作实际上没有发生。可以用一些简单的方法来避免这个问题。
在 Java 中,如果不是64位版本的,JVM 会把 double 或者 long 的读和写划分在两个 32 位中,这样一来,在多线程中,没有声明是 volatile 的 double 或者 long 也是不安全的。
锁是同步和互斥的,同样也是内存可见的。为了避免出现读到过期的数据,读和写的线程都要使用公共的锁进行同步。
volatile 是一种弱同步,只能保证可见性,而不能保证原子性。(为了安全,可以理解成 volatile 基本上只能使 boolean 的值原子化,像自增这种操作是不能被 volatile 原子化的)在确保 volatile 变量所引用状态的可见性、标识重要的生命周期事件(初始化或者关闭)的时候可以用,其他的时候最好不要用。下面数绵羊的代码就是一种典型的应用:
volatile boolean asleep;
...
while(!asleep) {
count();
}
如果有其他的线程修改了 asleep, 让它变成 true 了,那么就会跳出循环。
不要在构造函数中启动线程,有可能造成溢出。用单独的 start() 或者 init() 启动线程
对于只在一个线程内使用的数据就没必要同步了,对于可以用 volatile(只有一个线程写入的变量),或者可以用栈限制:
public in loadTheArk(Collection<Animal> cadidates) {
SortedSet<Animal> animals;
int numPairs = 0;
Animal candidate = null;
// new 了一个集合来装 cadidates,避免溢出
animals = new TreeSet<>(new SpeciesGenderComparator());
animals.addAll(candidates);
... // count numPairs
}
也可以用更规范的方法 ThreadLocal 把线程和持有数值的对象关联在一起。但是这种方法开销比较大。
不可变的对象是线程安全的,它必须满足:
- 它的状态在创建后不能被修改
- 所有的域都是 final 的
- 被正确的创建(创建期间没有发生 this 引用的溢出)
对象发布时,应该使用同步。但是对于不可变对象来说,可以不用同步。为了安全的发布对象,可以:
- 静态初始化对象的引用
- 把它的引用存储到 volatile 域或者 AtomicReference
- 把它的引用存储到正确创建对象的 final 域中
- 把它的引用存储到由正确锁保护的域中
如果对象本身是可变的,但是发布之后状态不会被修改,那么就在发布的时候对所有线程可见,之后线程访问这个对象就不需要额外的同步了。如果后续状态会被改变,那么必须是线程安全或者锁保护的。
Java 并发之共享对象的更多相关文章
- java并发之固定对象与实例
java并发之固定对象与实例 Immutable Objects An object is considered immutable if its state cannot change after ...
- 【翻译十五】-java并发之固定对象与实例
Immutable Objects An object is considered immutable if its state cannot change after it is construct ...
- 《Java并发编程实战》学习笔记 线程安全、共享对象和组合对象
Java Concurrency in Practice,一本完美的Java并发参考手册. 查看豆瓣读书 推荐:InfoQ迷你书<Java并发编程的艺术> 第一章 介绍 线程的优势:充分利 ...
- 【Java并发.3】对象的共享
本章将介绍如何共享和发布对象,从而使他们能够安全地由多个线程同时访问.这两章合在一起就形成了构建线程安全类以及通过 java.util.concurrent 类库来构建开发并发应用程序的重要基础. 3 ...
- 【Java并发编程一】线程安全和共享对象
一.什么是线程安全 当多个线程访问一个类时,如果不用考虑这些线程在运行时环境下的调度和交替执行,并且不需要额外的同步及在调用代码代码不必作其他的协调,这个类的行为仍然是正确的,那么称这个类是线程安全的 ...
- java并发程序和共享对象实用策略
java并发程序和共享对象实用策略 在并发程序中使用和共享对象时,可以使用一些实用的策略,包括: 线程封闭 只读共享.共享的只读对象可以由多个线程并发访问,但任何线程都不能修改它.共享的只读对象包括不 ...
- 深入理解Java并发之synchronized实现原理
深入理解Java类型信息(Class对象)与反射机制 深入理解Java枚举类型(enum) 深入理解Java注解类型(@Annotation) 深入理解Java类加载器(ClassLoader) 深入 ...
- Java并发之synchronized
Java多线程同步关键词是常用的多线程同步手段.它可以修饰静态类方法,实例方法,或代码块.修饰static静态方法时是对整个类加锁. 一.实现原理 在JVM中对象内存分三块区域,对象头.实例数据.对齐 ...
- 《提升能力,涨薪可待》—Java并发之Synchronized
Synchronized简介 线程安全是并发编程中的至关重要的,造成线程安全问题的主要原因: 临界资源, 存在共享数据 多线程共同操作共享数据 而Java关键字synchronized,为多线程场景下 ...
随机推荐
- javascript进阶——分离式DOM脚本编程
编写分离式(unobstrusive)代码意味着对HTML内容的完全分离:数据来自服务器端,javascript代码用来动态化和交互.这种分离的好处是在不同浏览器之间使用是可以完全降级或升级运行,对于 ...
- nginx中的try_files指令解释
try_files 指令的官方介绍比较让人摸不着头脑,经网上一番总结查看,try_files最核心的功能是可以替代rewrite. try_files 语法: try_files file . ...
- 2016032901 - ubuntu安装jdk
在ubuntu上安装jdk,然后网上大部分相同的教程配置,结果运行java,javac,java -version总是出现莫名奇妙的问题. 原先配置完之后,运行java -version后出现下面内容 ...
- shell写的计算器
#!/bin/bashif [ $# -ne 3 ] then echo "Usage: $0 num1 + num2" fi case $2 in +) echo $1$2$3= ...
- MVC-内容详情页显示内容
@model InfoDataProvider.DataModel.FAQ_ContentUser 内容Content字段:如果里面有html标签. @Html.DisplayFor(p => ...
- WIN32api总结
1.鼠标操作: win32api.SetCursorPos((101,156)) win32api.mouse_event(win32con.MOUSEEVENT_LEFTDOWN,0,0,0,0) ...
- 关于新的man版本出现“无法解析 /usr/share/man/zh_CN/man1/ls.1.gz: 没有那个文件或目录“
今天学习了下man,有关详细资料参考:http://www.cnblogs.com/hnrainll/archive/2011/09/06/2168604.html toor@door:/usr/sh ...
- System.out.println(对象)
class Person { private String name; private int age; public String getName() { return this.name; } p ...
- UVA 825 Walkiing on the safe side
根据地图,要求固定两点间最短路径的条数 . 这题的输入数据就是个坑,题目有没有说明数据之间有多个空格,结尾换行符之前也不止一个空格,WA了好几遍,以后这种情况看来都要默认按照多空格的情况处理了. 可以 ...
- Android ListView(Selector 背景图片 全选 Checkbox等按钮)
list_item.xml <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xm ...