安卓开发(Java)中关于final关键字与线程安全性
前言
学习新知识固然重要,但是时常往回看看,温故知新是很必要的。回顾一下线程安全性和final关键字。
正文
从Java 5开始,final keyword一个特殊用法是在并发库中一个非常重要且经常被忽视的武器。实质上,可以使用final来确保在构造对象时,访问该对象的另一个线程不会看到处于部分构造状态的对象,否则可能会发生这种情况。这是因为当作为对象变量的一个属性时,final作为其定义的一部分具有以下重要特征:
当构造函数退出时,final keyword的值保证对访问构造对象的其他线程可见。
使用final是所谓的安全发布(safe publication)的一种方式,这里,发布(publication)一个地相意味着在一个线程中创建它,同时另一个线程在之后的某时刻可以引用到该新创建的对象。当JVM调用对象的构造函数时,它必须将各成员赋值,同时存储一个指向该对象的指针。就像其他任何的数据写入一样,这可能是乱序的,and their application to main memory can be delayed and other processors can be delayed unless you take special steps to combat this(看不太懂,是不是说“把他们写回主存可能推迟,并且其他的处理器(看到变化)也会推迟,要客服这一点,除非采取非常步骤”)。特别的,指向对象的引用可能在成员变量提交之前(导致如此的原因之一是编译器的指令重排ordering:if you think about how you'd write things in a low-level language such as C or assembler, it's quite natural to store a pointer to a block of memory, and then advance the pointer as you're writing data to that block)就被写入到主存并被访问到了。这样会导致另一个线程看到了一个不合法或不完整的对象。
而final可以防止此类事情的发生:如果某个成员是final的,JVM规范做出如下明确的保证:一旦对象引用对其他线程可见,则其final成员也必须正确的赋值了。
final的对象引用
对象的final成员成员的值在当退出构造函数时,他们也是最新的。这意味着:
final类型的成员变量的值,包括那些用final引用指向的collections的对象,是读线程安全而无需使用synchronization的
注意,如果你有一个指向collection,数组或其他可变对象的final引用,如果存在其他线程访问,仍然需要使用同步机制来访问该对象(或使用ConcurrentHashMap)。
因此,不可变对象(指所有的成员都是final并且成员要么是基本类型,要么指向另一个不可变对象)可以并发访问而无需使用同步机制。通过final引用读取“实际不可变”对象(指成员虽然实际并不是final,然而却从不会改变)也是安全的。然而,从程序设计的角度来看,在此种情况下强化不可变性是明智的(如用Collections.unmodifiableList()封装一个collection)。That way, you'll spot bugs introduced when one of your colleagues naughtily attempts to modify a collection that you didn't intend to be modified!
使用final的限制条件和局限性
当声明一个final成员时,必须在构造函数退出前设置它的值,如下:
public class MyClass {
private final int myField = 3;
public MyClass() { ... }
}
或者
public class MyClass {
private final int myField;
public MyClass() {
...
myField = 3;
...
}
}
需要强调的是将指向对象的成员声明为final只能将该引用设为不可变的,而非所指的对象。例如如果一个list声明如下:
private final List myList =new ArrayList();
仍然可以修改该list
myList.add("Hello");
然而,声明为final可以保证如下操作不合法:
myList =new ArrayList();
myList= someOtherList;
什么时候应该使用final
一个答案就是“尽可能的使用”。任何你不希望改变的(基本类型,或者指向一个对象,不管该对象是否可变)一般来讲都应该声明为final。另一种看待此问题的方式是:
如果一个对象将会在多个线程中访问并且你并没有将其成员声明为final,则必须提供其他方式保证线程安全
“其他方式”可以包括声明成员为volatile,使用synchronized或者显式Lock控制所有该成员的访问。
大家往往忽视的典型case是在一个线程创建一个对象,而后在另一个线程使用,如一个通过ThreadPoolExecutor的对象。这种情况下,必须保证该对象的线程安全性:这和线程的并发访问关系不大,主要是因为在其生命周期内,不同的线程会在任意时刻访问它(还是内存模型的问题吧)
作者:AirrWang
链接:https://www.jianshu.com/p/ba764ca54262
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
安卓开发(Java)中关于final关键字与线程安全性的更多相关文章
- 浅析Java中的final关键字(转载)
自http://www.cnblogs.com/dolphin0520/p/3736238.html转载 一.final关键字的基本用法 在Java中,final关键字可以用来修饰类.方法和变量(包括 ...
- 关于Java中的final关键字
Java中的final关键字是用来限制用户行为的,说白了,就是用来限制我们这些程序员的.final可以用来修饰:变量.方法.类. 1)Java final variable final用来修饰变量时, ...
- 深入理解Java中的final关键字
Java中的final关键字非常重要,它可以应用于类.方法以及变量.这篇文章中我将带你看看什么是final关键字?将变量,方法和类声明为final代表了什么?使用final的好处是什么?最后也有一些使 ...
- 浅析Java中的final关键字
浅析Java中的final关键字 谈到final关键字,想必很多人都不陌生,在使用匿名内部类的时候可能会经常用到final关键字.另外,Java中的String类就是一个final类,那么今天我们就来 ...
- (转)深入理解Java中的final关键字
转自:http://www.importnew.com/7553.html Java中的final关键字非常重要,它可以应用于类.方法以及变量.这篇文章中我将带你看看什么是final关键字?将变量,方 ...
- [转载]浅析Java中的final关键字
浅析Java中的final关键字 谈到final关键字,想必很多人都不陌生,在使用匿名内部类的时候可能会经常用到final关键字.另外,Java中的String类就是一个final类,那么今天我们就来 ...
- 转载:浅析Java中的final关键字
谈到final关键字,想必很多人都不陌生,在使用匿名内部类的时候可能会经常用到final关键字.另外,Java中的String类就是一个final类,那么今天我们就来了解final这个关键字的用法.下 ...
- java中的final关键字
谈到final关键字,想必很多人都不陌生,在使用匿名内部类的时候可能会经常用到final关键字.另外,Java中的String类就是一个final类,那么今天我们就来了解final这个关键字的用法.下 ...
- 浅析Java中的final关键字(转)
谈到final关键字,想必很多人都不陌生,在使用匿名内部类的时候可能会经常用到final关键字.另外,Java中的String类就是一个final类,那么今天我们就来了解final这个关键字的用法.下 ...
随机推荐
- NET定时任务组件Hangfire
开源的.NET定时任务组件Hangfire解析 项目慢慢就要开工了,很多园友都在问这个事情,看来大伙对这事很上心啊,事情需要一步步的来,尽量写出一个我们都满意的项目.以前每次在博客前面都会扯淡一下,不 ...
- 【BZOJ】3456: 城市规划(多项式求ln)
题解 在我写过分治NTT,多项式求逆之后 我又一次写了多项式求ln 我们定义一个数列的指数型生成函数为 \(\sum_{i = 0}^{n} \frac{A_{i}}{i!} x^{i}\) 然后这个 ...
- 000 关于IDEA的基本环境配置以及快速使用(git拉载程序,Jdk安装,tomcat部署,应用程序打包运行)
刚开始工作的时候,不熟悉,所以整理过这个文档. 一:导入git程序 1.准备 git链接 IDEA软件,最好是终极版 2.第一步选择从版本控制上选择git 3.拷贝源于目标地址 4.这时候根据引导进行 ...
- DJANGO ADMIN 一些有用的设置(转)
DJANGO ADMIN 一些有用的设置 Django自带的后台管理是Django明显特色之一,可以让我们快速便捷管理数据.后台管理可以在各个app的admin.py文件中进行控制.以下是我最近摸 ...
- [转]KMP算法
KMP算法应该是每一本<数据结构>书都会讲的,算是知名度最高的算法之一了,但很可惜,我大二那年压根就没看懂过~~~ 之后也在很多地方也都经常看到讲解KMP算法的文章,看久了好像也知道是怎么 ...
- strlen()和mb_strlen()
换行需要用双引号,单引号只会输出字符. strlen()返回字符串所占的字节数,对于utf8编码的中文,一个汉字占三个字节. mb_strlen()返回字符个数,如果不写第二个参数,就会使用内部编码, ...
- django权限管理
当我们为应用创建一个Models, 在同步到数据库里,django默认给了三个权限 ,就是 add, change, delete权限. 首先,我们创建一个perm_test的project, 然后再 ...
- 喵哈哈村的魔法考试 Round #4 (Div.2) 题解
有任何疑问,可以加我QQ:475517977进行讨论. A 喵哈哈村的嘟嘟熊魔法(1) 题解 这道题我们只要倒着来做就可以了,因为交换杯子是可逆的,我们倒着去模拟一遍就好了. 有个函数叫做swap(a ...
- 【原】使用Eclipse远程Debug测试环境
[环境参数] Eclipse:Version: Mars.2 Release (4.5.2) Linux:centOS 6.5 [简述] Java自身支持调试功能,并提供了一个简单的调试工具--JDB ...
- spring-boot 速成(3) actuator
actuator 通过暴露一系列的endpoints可以让开发者快速了解spring boot的各项运行指标,比如:线程数,jvm剩余内存等一系列参数. 启用方法很简单,参考下面: dependenc ...