- Contents
- 为什么final在多线程中是必要的
- final对象的引用
- final的局限性
- 什么时候需要使用final
自java 5 起, final关键词在并发中的一个特殊应用是非常重要而且常常被忽视的,实际上,fianl 可以保证正在创建中的对象不能被其他线程访问到,反之,不适用final的对象,是可以在创建的过程中被访问到的。因为,当一个对象的变量被用作属性的时候,final有以下重要的特征:
当构造函数退出时,final域的值是被保证对其他线程可见的。
- 为什么这是必要的?
final域是一种被叫做“安全发布”的方式。对象的发布是指-在一个线程中创建一个对象,这个最新被创建的对象在未来的某个时刻被另外一个线程引用。当JVM执行对象的构造方法时,它必须将值存储到对象的各个域,并存储一个对象的指针。在其他任何情况下的数据写入(这种写入可能是无序的),访问主内存的应用程序可能被延迟,其他处理器的应用程序也可能被延迟,除非使用特殊的步骤确保这种延迟不发生。(这里是指对共享对象并发数据的写入存在竞态条件,事实上这种共享对象的并发写入,最终结果取决于最线程的执行顺序)尤其是,对象数据的指针可能存储在主存中,然后在对象的域提交之前被访问(这件事发生部分是因为编译指令如果你熟悉用低级语言,比如C或者汇编,来编写程序,很自然你会为一块内存分配一个指针,当你想向这块内存中写数据的时候就通过指针来操)。这种情况下会使得其他的线程可以访问到一个无效的或者是部分被创建的对象。
声明为final 可以防止这种情况(其它线程访问到部分对象)的发生:
final域:final域可以有效的避免竞态条件的发生是JVM规范的一部分,一旦对象的指针对其他线程是可见的,这个对象的final域的正确的值对其他对象也是可见的
- final对象引用
通过final引用访问的任何对象的域 也可以保证 是和构造函数退出时一样是最新的:
final域的值,包括collection中引用的final对象,不需要使用synchronized在读取数据时可以保证是线程安全的
注意:如果有一个对collection的final引用,array 或者其他可变的对象,在多线程访问的情况下仍然需要同步所有的访问,(或者可以使用线程安全的类,如CurrentHashMap)。
因此,对于不可变对象(所有域都是final 并且创建后没有被修改,或者指向一个不可变对象)都可以被并发访问而不需要同步。
通过final引用对于那些“实际上不变”的对象的读取操作也是安全的,(实际上不变的对象是指域不是final的,但是创建之后没有被改变过)。但是从程序设计的角度来讲,最好声明为final的。
- final的局限性
final域在声明的时候,这个域必须在构造函数退出之前被初始化完成。有两种方式可以初始化final域:
(1)
public class MyClass {
private final int myField = 3;
public MyClass() {
...
}
private final int myField = 3;
public MyClass() {
...
}
}
(2)
public class MyClass {
private final int myField;
public MyClass() {
...
myField = 3;
...
}
private final int myField;
public MyClass() {
...
myField = 3;
...
}
}
必须强调的一点是,当声明一个final的引用时, 只能说明该引用是不可变的,但是数据是可变的。比如声明一个final 的list:
private final List myList = new ArrayList();
你仍然可以改变这个list:
myList.add("Hello");
然而下面的操作是不允许的:
myList = new ArrayList();
myList = someOtherList;
- 什么时候需要使用final
一种说法是:任何不希望域被改变的时候都可以使用final
另外一种是:如果一个对象可以被多个线程访问到,但是并没有被声明为final,那么你需要提供额外的线程安全机制。
其他的方式包括声明为volatile 、使用synchronized、显示锁等
一种典型的应用是:在一个线程中创建一个对象,然后对象呗另一个线程使用,比如通过 ThreadPoolExecutor, 在这种情况下,必须要确保对象是线程安全的,这无关访问是不是并发的,而是关于对象在生命周期中的任何时候被多个线程访问。
更多 参考final的内存模型:
相关推荐
多线程环境下,多个线程可能会共享某些资源,因此需要对这些资源进行同步处理以避免竞态条件和死锁等问题。 1. **使用`synchronized`关键字**:可以修饰方法或者代码块,确保同一时刻只有一个线程可以访问被标记为...
`volatile`关键字用于保证变量在多线程环境中的可见性,并防止指令重排序。当一个变量被声明为`volatile`时,每次读取都会从主内存中获取,而不是从线程的工作内存,确保所有线程看到的都是最新值。同时,`volatile`...
49. `volatile` - 用于共享变量,保证多线程环境下的可见性和一致性。 50. `while` - 循环控制结构。 接下来,我们关注Java中的3个基本直接量类型: 1. **数值直接量**:这些是直接表示数值的常量,包括整型(如...
标题中的"Process.Explorer11.33_yfy_final"指的是Process Explorer的11.33版本,由用户"yfy"进行了汉化,使得非英文环境下的用户也能轻松使用。 **1. 功能特性** - **进程详细信息**:Process Explorer 显示了每...
相比之下,`HashMap` 的默认实现是非线程安全的,如果要在多线程环境中使用,需要额外的同步措施。 - `HashMap` 提供了一些额外的方法,如 `containsValue()` 和 `containsKey()`,这些方法在 `Hashtable` 中已被弃...
- **final变量在并发编程中的应用**:final变量在多线程环境中具有特殊的语义,线程可以安全地读取,因为它们是不可变的。 - **volatile与final**:在某些情况下,volatile和final一起使用可以保证线程间的可见性...
21. Struts的Servlet不是线程安全的,因此在多线程环境下需要额外处理。 22. Struts实现了MVC模式,通过Action类处理请求,视图由JSP或其他模板技术呈现,模型由业务对象和数据访问对象组成。 23. MVC的实现通常由...
属于类而非类的实例final用于声明不可变的变量,或者防止类或方法被重写abstract用于声明抽象方法或抽象类synchronized使方法或代码块同步,确保同一时间只有一个线程执行volatile保证多线程环境中的变量可见性和...
但是,`HashMap` 是非线程安全的,这意味着在多线程环境中使用时需要额外的同步措施。 - **Hashtable**:也是基于哈希表的 Map 接口实现,但不允许任何键或值为 null。此外,`Hashtable` 是线程安全的,即所有方法...
42. `synchronized`:同步修饰符,用于多线程环境下的安全访问。 43. `this`:当前对象的引用,用于区分成员变量和局部变量。 44. `throw`:抛出一个异常,中断程序正常流程。 45. `throws`:声明方法可能抛出的异常...
47. `volatile`: 修饰符,确保多线程环境下的可见性和不被优化,保证变量在不同线程间的一致性。 48. `while`: 创建while循环,当条件为真时持续执行循环体。 这些关键字是构建Java程序的基础,理解并熟练运用它们...
- 线程安全是指当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程将如何交替执行,并且在主调代码中不需要额外的同步及协作,这个类都能表现正确的行为。 综合上述知识点,可以发现这份文档中...
在JDK 1.4及更高版本中,引入了非阻塞I/O库`java.nio`,它可以显著提升并发I/O性能,避免因创建大量线程而导致的开销。对于旧版本JDK,可以寻找第三方库来实现非阻塞I/O。 3. **谨慎使用异常**: 异常处理是昂贵...
在局域网环境下,玩家可以通过网络连接进行实时对战,这涉及到网络编程中的TCP/IP协议、Socket通信和多线程技术。同时,“简单”一词表明该程序可能采用了基础的设计模式,易于理解和学习,适合初学者研究。 【标签...
- **减少实例变量的使用**:尽可能将数据存储在局部变量中,特别是在循环等高频使用的场景下。 **1.7 乘法和除法** 在一些计算密集型的应用中,使用位运算代替乘法和除法可以显著提高性能。 - **位运算代替乘除**...
- **重点概述**:本文将详细介绍如何在Android应用中使用线程来处理后台任务,并通过`android.os.Handler`类来实现在非UI线程中更新用户界面。 - **应用场景**:在实际开发过程中,当需要执行耗时操作(例如下载...
两者都是线程安全的字符串操作类,但在非多线程环境下,StringBuilder更高效,因为它不进行同步操作。 35. **AOP的用途**: AOP用于日志记录、事务管理、权限控制等功能,将这些横切关注点与业务逻辑分离。 36. ...
这样做是为了保持字符串的不可变性,从而确保在多线程环境中字符串的安全性。 #### 五、抽象类与接口 - **抽象类**: - 可以包含抽象方法和非抽象方法。 - 可以包含实例变量。 - 提供了一种基础类,允许子类继承...
- 评价其在项目中使用的分值系统,如1-5分,以量化他们的技术掌握程度。 2. **技术选型与优缺点分析**: - 弄清楚项目中所使用的技术栈和框架,判断他们是否理解技术背后的动机。 - 讨论技术的优缺点,看他们...
受保护区域是指在多线程环境中,为了防止并发访问而导致的数据不一致性,而使用同步机制(如锁)保护的代码段。通过确保每次只有一个线程可以访问受保护区域,可以有效地避免竞态条件。 #### 33. 堆 (Heap) 堆是...