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,为多线程场景下 ...
随机推荐
- linux点滴:NFS
介绍 NFS,Network File System,网络文件系统.主要功能是通过网络让不同的主机系统间共享资源,类似于windows下的文件共享.适用于互联网中小型企业. 工作原理 客户端发送请求 ...
- LocalContainerEntityManagerFactoryBean
http://doc.okbase.net/liuyitian/archive/109276.html
- MVC-简单验证码制作
1.制作验证码: using System; using System.Collections.Generic; using System.Drawing; using System.Drawing. ...
- 在图层上使用CATransform3D制做三维动画-b
在UIView上,我们可以使用CGAffineTransform来对视图进行:平移(translation),旋转(Rotation),缩 放(scale),倾斜(Invert)操作,但这些操作是没有 ...
- Windows 2008 故障转移群集介绍
转载:http://dufei.blog.51cto.com/382644/902026 今天有客户问起Windows 群集的相关内容,毕竟Windows Server2008所支持的群集技术和Win ...
- BZOJ 3992 [SDOI 2015] 序列统计 解题报告
这个题最暴力的搞法就是这样的: 设 $Dp[i][j]$ 为前 $i$ 个数乘积为 $j$ 的方案数. 转移的话就不多说了哈... 当前复杂度 $O(nm^2)$ 注意到,$M$ 是个质数,就说明 $ ...
- 年度十佳 DevOps 博客文章(后篇)
如果说 15 年你还没有将 DevOps 真正应用起来,16 年再不实践也未免太落伍了.在上篇文章中我们了解到 15 年十佳 DevOps 博客文章的第 6-10 名,有没有哪一篇抓住了您的眼球,让您 ...
- 获取保存在沙盒中plist文件的用户的字典信息
获取保存在沙盒中plist文件的用户的字典信息
- *[topcoder]AstronomicalRecords
http://community.topcoder.com/stat?c=problem_statement&pm=12804&rd=15706 首先A和B的长度都不一定一样,里面的元 ...
- SPRING IN ACTION 第4版笔记-第八章Advanced Spring MVC-003-Pizza例子的基本流程
一. 1. 2.pizza-flow.xml <?xml version="1.0" encoding="UTF-8"?> <flow xml ...