Thread-safety with the Java final
keyword
来源于:http://www.javamex.com/tutorials/synchronization_final.shtml
As of Java 5, the final
keyword is a very important and often overlooked(漏看,忽略
) weapon in your
concurrency armoury(军械库;武器厂
). Essentially, final
can be used to make sure that when you
construct an object, another thread accessing that object doesn't see that object
in a partially-constructed state, as could otherwise happen.
This is because when used as an attribute on the variables of an object, final
has the following important characteristic as part of its definition:
When the constructor exits, the values of final fields are guaranteed to be visible to other threads accessing the constructed object.
Why is this necessary?
The final
field is a means of what is sometimes called safe publication
.
Here, "publication" of an object means creating it in one thread and then having
that newly-created object be referred to by another thread at some point in the future.
When the JVM executes the constructor of your object, it must store values into
the various fields of the object, and store a pointer to the object data. As in any
other case of data writes, these accesses can potentially occur out of order, and their
application to main memory can be delayed and other processors can be delayed unless you
take special steps to combat this.
In particular, the pointer to the object data could be stored to main memory and
accessed before
the fields themselves have been committed
(this can happen partly because of compiler 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).
And this in turn could lead to another
thread seeing the object in an invalid or partially constructed state.
final
prevents this from happening:
if a field is final
, it is part of the JVM specification that it must effectively ensure
that, once the object pointer is available to other threads, so are the correct values
of that object's final fields.
Final object references
The fields on any object
accessed via a final
reference are also
guaranteed to be at least as up to date(最新的,最近的
) as when the constructor exits. This means that:
Values of final fields, including objects inside collections referred to by a final reference, can be safely read without synchronization.
Note that if you have a final
reference to a collection, array, or some
other mutable object, you must still synchronize all accesses to that object (or use
a thread-safe collection such as a ConcurrentHashMap
)
if that collection is ever accessed by a thread other than the constructing thread.
Thus, immutable objects
(ones where all fields are final
and are
either primitives or references to immutable objects)
can be concurrently accessed without synchronization
. It is also safe to
read "effectively immutable" objects (ones whose fields aren't actually final, but
in practice never change) via a final
reference. However, from a program design
perspective, you'd be wise to try and enforce immutability in this case (e.g. by
wrapping a collection in a Collections.unmodifiableList()
1
etc). 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!
Restrictions and limitations of using final
When you declare a field final
, you must
set the value once
by the time the constructor exits
. This means that you can declare a
final field as follows:
public class MyClass {
private final int myField = 3;
public MyClass() {
...
}
}
or
you can write the following:
public class MyClass {
private final int myField;
public MyClass() {
...
myField = 3;
...
}
}
It's important to emphasise that storing a reference to an object in a final
field only makes the reference
immutable
, not the actual object.
For examlple,
if a list is declared as follows:
private final List myList = new ArrayList();
there's nothing to stop modifications to the list:
myList.add("Hello");
However, the following would not
be possible:
myList = new ArrayList();
myList = someOtherList;
When should I use final
?
One answer to this is "whenever you possibly can". Any field that you never expect to be
changed (be that a primitive value, or a reference
to an object, whether or not
that particular object is itself immutable or not), should generally
be declared final
. Another way of looking at things is:
If your object is accessed by multiple threads, and you don't declare its fields final, then you must provide thread-safety by some other means.
Other means could include declaring the field volatile
,
using synchronized
or
an explicit Lock
around all accesses to that field.
A typical case that people overlook is where an object is created by one thread
and then later
consumed by another thread, e.g. an object via a
ThreadPoolExecutor
.
In this case, the object must still be
made properly thread-safe: it doesn't matter that the accesses by different threads aren't
concurrent
. What matters is that the object is accessed by different threads at
any
point in its lifetime.
分享到:
相关推荐
Java Persistence API 2.0-final-spec 免费下载
赠送原API文档:jboss-threads-3.1.0.Final-javadoc.jar; 赠送源代码:jboss-threads-3.1.0.Final-sources.jar; 赠送Maven依赖信息文件:jboss-threads-3.1.0.Final.pom; 包含翻译后的API文档:jboss-threads-...
5GAA-Road-safety-FINAL2017-12.pdf
SPVMN 视频监控联网调测软件完整版(mss-1.4.0.FINAL-apache-tomcat-6.0.29) SPVMN 视频监控联网调测软件完整版(mss-1.4.0.FINAL-apache-tomcat-6.0.29)
hibernate-commons-annotations-4.0.1.Final.jar hibernate-core-4.1.12.Final.jar hibernate-ehcache-4.1.12.Final.jar hibernate-entitymanager-4.1.12.Final.jar hibernate-jpa-2.0-api-1.0.1.Final.jar ...
Eclipse中Hibernate插件。
赠送原API文档:netty-buffer-4.1.68.Final-javadoc.jar; 赠送源代码:netty-buffer-4.1.68.Final-sources.jar; 赠送Maven依赖信息文件:netty-buffer-4.1.68.Final.pom; 包含翻译后的API文档:netty-buffer-4.1....
赠送原API文档:hibernate-jpa-2.1-api-1.0.2.Final-javadoc.jar; 赠送源代码:hibernate-jpa-2.1-api-1.0.2.Final-sources.jar; 赠送Maven依赖信息文件:hibernate-jpa-2.1-api-1.0.2.Final.pom; 包含翻译后的...
Eclipse用于Hibernate框架开发插件,全CSDN最低资源分下载,让你吃上真正的石灰。。。
mss-1.4.0.FINAL-apache-tomcat-6.0.29 此为28181新版调测软件,按照 连接说明(在压缩包里面)来安装解包就可以调试了
赠送原API文档:validation-api-2.0.1.Final-javadoc.jar; 赠送源代码:validation-api-2.0.1.Final-sources.jar; 赠送Maven依赖信息文件:validation-api-2.0.1.Final.pom; 包含翻译后的API文档:validation-api...
java Excel文件 poi-bin-3.1-FINAL-20080629
这里有poi-2.0-final,poi-3.2-final两个版本,希望对大家有帮组
赠送原API文档:jboss-logging-3.4.1.Final-javadoc.jar; 赠送源代码:jboss-logging-3.4.1.Final-sources.jar; 赠送Maven依赖信息文件:jboss-logging-3.4.1.Final.pom; 包含翻译后的API文档:jboss-logging-...
赠送原API文档:netty-all-4.1.23.Final-javadoc.jar; 赠送源代码:netty-all-4.1.23.Final-sources.jar; 赠送Maven依赖信息文件:netty-all-4.1.23.Final.pom; 包含翻译后的API文档:netty-all-4.1.23.Final-...
Java 多线程与并发(6_26)-关键字_ final详解
ClassFinal是一款java class文件安全加密工具,支持直接加密jar包或war包,无需修改任何项目代码,兼容spring-framework;可避免源码泄漏或字节码被反...执行java -jar classfinal-fatjar.jar 后按提示即可完成加密。
赠送原API文档:undertow-websockets-jsr-2.1.7.Final-javadoc.jar; 赠送源代码:undertow-websockets-jsr-2.1.7.Final-sources.jar; 赠送Maven依赖信息文件:undertow-websockets-jsr-2.1.7.Final.pom; 包含翻译...
PLX公司最新PCI开发工具包 2014-03-04 文件较大,请下载2个完整压缩包 PLX_SDK_v7_11_Final_2014-03-04.part1.rar PLX_SDK_v7_11_Final_2014-03-04.part2.rar
赠送原API文档:netty-codec-http-4.1.27.Final-javadoc.jar; 赠送源代码:netty-codec-http-4.1.27.Final-sources.jar; 赠送Maven依赖信息文件:netty-codec-http-4.1.27.Final.pom; 包含翻译后的API文档:netty...