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,为多线程场景下 ...
随机推荐
- Static File Middleware
[ASP.NET Core] Static File Middleware 前言 本篇文章介绍ASP.NET Core里,用来处理静态档案的Middleware,为自己留个纪录也希望能帮助到有需要 ...
- Python之创建单元素tuple
tuple和list一样,可以包含 0 个.1个和任意多个元素. 包含多个元素的 tuple,前面我们已经创建过了. 包含 0 个元素的 tuple,也就是空tuple,直接用 ()表示: >& ...
- python 内置函数 getattr
class Getattr_Test(): var_a = 'abc' def methodA(self): var_b = 'xyz' return var_b t = Getattr_Test() ...
- 练习--LINUX进程间通信之信号SIGNAL
同样的,信号也不要太迷信可靠信号及不及靠信号,实时或非实时信号. 但必须要了解这些信号之间的差异,函数升级及参数,才能熟练运用. ~~~~~~~~~~~~~~~~ 信号本质 信号是在软件层次上对中断机 ...
- POJ2225+BFS
简单的BFS 1a /* 从起点到终点 */ #include<stdio.h> #include<string.h> #include<stdlib.h> # ...
- MySQL表结构为InnoDB类型从ibd文件恢复数据
客户的机器系统异常关机,重启后mysql数据库不能正常启动,重装系统后发现数据库文件损坏,悲催的是客户数据库没有进行及时备份,只能想办法从数据库文件当中恢复,查找资料,试验各种方法,确认下面步骤可行: ...
- 李洪强iOS开发本人集成环信的经验总结_01环信SDK的导入
李洪强iOS开发本人集成环信的经验总结_01环信SDK的导入 01 - 直接在项目中导入SDK和一些静态库 这个时候,没有错误的编译没有错误的话,就说明SDK已经配置成功 还有一种方法是用cocoap ...
- github Git 原理简介
由于Git是一个DVCS(Distributed Version Control System,分布式版本控制系统),不同于传统的CVS/SVN版本系统那样必须由一个中央服务器来管理所有的版本记录,它 ...
- Altium快捷键
M快捷键 PCB快捷键 编辑 视图
- 屏幕尺寸,屏幕分辨率,屏幕密度,各种长宽单位(px,sp,dp,in.pt,mm)
常见长宽单位表 名称 单位缩写 单位全拼 介绍 屏幕尺寸 '' 或 in inch 屏幕的大小,通常用屏幕对角线的长度表示.单位是寸 屏幕分辨率 px pixels 整个屏幕的像素数,一般用屏幕的像素 ...