`

java final 与 线程安全(Thread-safety)

阅读更多

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多线程与线程安全实践-基于Http协议的断点续传

    在Java编程领域,多线程和线程安全是至关重要的概念,特别是在开发高效、响应迅速的应用程序时。本文将深入探讨如何在Java中实现多线程,并结合HTTP协议实现断点续传功能,以提高文件下载的效率和用户体验。 首先,...

    JAVA源码JAVA多线程与线程安全实践-基于Http协议的断点续传

    ### JAVA多线程与线程安全实践:基于HTTP协议的断点续传 #### 多线程基础 在深入探讨如何实现基于HTTP协议的断点续传之前,我们首先需要了解一些关于Java多线程的基础知识。Java多线程是Java编程语言的一个核心...

    hibernatetools-Update-4.1.1.Final_2013-12-08_01-06-33-B605.zip

    总之,"hibernatetools-Update-4.1.1.Final_2013-12-08_01-06-33-B605.zip"是一个强大的Eclipse插件,它为Java开发者提供了全面的Hibernate支持,使数据库操作和管理变得轻松高效。无论是新手还是经验丰富的开发者,...

    Java线程间的通信----生产者消费者模型

    在Java编程中,线程间的通信是多线程编程中的一个重要概念,特别是在处理并发和协作任务时。生产者消费者模型是一种经典的线程同步问题,它模拟了实际生活中的生产过程和消费过程,使得生产者线程可以将数据生产出来...

    Java并发中的线程安全性

    为了确保程序在多线程环境下的正确性,理解线程安全性(Thread Safety)至关重要。 #### 2. 线程安全性分析 ##### 2.1 定义与概念 线程安全性是指一个对象或类可以在多线程环境下被多个线程共享而不会导致数据不...

    Java 多线程与并发-Java并发知识体系详解.pdf

    Java并发编程是Java开发中的重要领域,涉及到多线程、并发控制、同步机制等多个知识点。以下是对Java并发知识体系的详细解析。 首先,我们要理解并发的理论基础。并发是为了提高系统资源利用率和处理能力,让多个...

    多线程 打印1-99,100-199

    在标准的 Java `Thread` 类中,`start()` 方法实际上会创建一个新的线程并调用 `Runnable` 接口中 `run()` 方法。因此,为了模拟这种行为,可以考虑在 `start` 方法中创建一个新的 `Thread` 对象,并传递当前对象...

    Netty (netty-3.2.5.Final.jar,netty-3.2.5.Final-sources.jar)

    这个压缩包包含 `netty-3.2.5.Final.jar` 和 `netty-3.2.5.Final-sources.jar` 两个文件,它们分别代表了Netty框架的运行时库和源代码。 `netty-3.2.5.Final.jar` 是Netty的可执行JAR文件,包含了所有必要的类和...

    validation-api-2.0.1.Final-API文档-中文版.zip

    赠送原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 多线程 订票 示例 线程安全

    本示例将探讨如何在Java中实现一个线程安全的订票系统。 首先,我们要理解什么是线程安全。线程安全是指当多个线程访问同一代码块时,即使这些线程是并发执行的,程序也能保持其正确性,即不会出现数据混乱或丢失的...

    Java 多线程与并发(6-26)-关键字- final详解.pdf

    Java多线程与并发(6-26)-关键字-final详解 本文将详细解释Java多线程与并发中关键字final的使用和实现原理,并讨论final的限制条件和局限性。 一、final关键字的基本使用 final关键字是Java语言中的一个关键字,...

    java多线程实现-tcp端口扫描

    Java提供了两种主要的线程创建方式:继承Thread类和实现Runnable接口。在本项目中,可能选择创建一个实现了Runnable接口的类,然后将其实例传递给Thread构造函数,创建新的线程实例。这样做可以避免单继承的限制,...

    Java多线程机制(示例)

    ### Java多线程机制详解与示例 #### 一、Java多线程机制概述 Java中的多线程机制是程序设计中的一个重要概念,它允许在同一个应用程序中并发执行多个线程,有效地提高了程序的执行效率和响应速度。通过Java语言...

    classfinal-fatjar-1.2.1.jar

    ClassFinal是一款java class文件安全加密工具,支持直接加密jar包或war包,无需修改任何项目代码,兼容spring-framework;可避免源码泄漏或字节码被反...执行java -jar classfinal-fatjar.jar 后按提示即可完成加密。

    Java多线程--让主线程等待所有子线程执行完毕

    为了解决上述问题,可以设计一个自定义的线程类,例如`ImportThread`,继承自`java.lang.Thread`。在这个类中,可以通过维护一个静态的`List<Thread>`集合来跟踪所有正在运行的子线程。当一个新线程启动时,它会将...

    Java 线程开发讲座

    #### 三、Java线程:线程栈模型与线程的变量 - **线程栈**:每个线程都有自己的独立栈空间,用于存储线程局部变量和方法调用信息。 - **线程变量**:使用`ThreadLocal`类可以为每个线程提供独立的变量副本,解决多...

    java多线程Thread-per-Message模式详解

    在Java多线程编程中,Thread-per-Message模式是一种常见的并发处理策略。这种模式的核心思想是为每个消息或任务创建一个新的线程来处理,使得消息的发送者和处理者不在同一个线程上下文中运行,从而实现任务的异步...

    Java多线程-解决单例模式中的懒汉式的线程安全问题

    ### Java多线程—解决单例模式中的懒汉式的线程安全问题 #### 一、单例设计模式的线程安全问题 ##### (1)饿汉式没有线程安全问题 **饿汉式**是一种非常典型的单例模式实现方式,其特点是在类加载时就完成了实例...

    poi-2.0-final和poi-3.2-final

    - "poi-2.0-final.jar" 和 "poi-3.2-final.jar":这些是Apache POI库对应的JAR文件,包含了所有必要的类和资源,可以直接在Java项目中引用,以便利用POI的功能。 **压缩包子文件的文件名称列表**: 虽然没有具体的...

    Java非线程安全类变线程安全类.pdf

    非线程安全类的例子可以是 NotThreadSafe 类,该类有一个共享变量 state,当多个线程使用同一个 NotThreadSafe 类的一个对象时,也会共享该对象的 state 属性,故是非线程安全的。 但是,通过一些改造也可以将非...

Global site tag (gtag.js) - Google Analytics