并发编程实战(5): 不变性、final与线程安全

不变性与final字段

如果某个对象在被创建后其状态就不能被修改,那么这个对象就被成为不可变对象。

在Java中,final类型的域是不能修改的。

不可变性不等于将对象中的所有域都声明为final类型,即使对象中的所有域都是final类型的,这个对象仍然是可变的,因为在final类型的域中保存对可变对象的引用。当满足以下条件时,对象才是不可变的:

  • 对象创建以后其状态就不能修改
  • 对象所有的域都是final类型
  • 对象是正确创建的(在对象创建期间,this引用没有逸出)

final表示无法将对象的引用更改为指向另一个引用或另一个对象,但仍然可以改变它的状态(例如使用setter方法)。不可变对象表示对象的实际值无法更改,但可以将其引用更改为另一个。

final修饰符适用于变量但不适用于对象,而不可变性适用于对象但不适用于变量。

声明final的类不可被继承。

下面举个例子:

final StringBuffer sb = new StringBuffer("hello");
sb.append("test");  // success
sb = new StringBuffer("hello world"); // failed

可以看到,sb虽然声明了final,但是仍然可以改变其值,但是不能将其指向另一个对象。

所以有以下结论:

  • 将引用变量声明为final,并不意味着该对象是不可变的。如果对象是不可变的,则无法完成上述追加操作。
  • final意味着无法分配新的内容给该引用变量,即前面提到的将对象的引用更改为指向另一个引用或另一个对象

线程安全

不可变对象一定是线程安全的。因为得到失效数据、丢失更新操作或者观察到某个对象处于不一致的状态等等问题,都与多线程试图同时访问同一个可变的状态相关。如果对象状态不会改变,那么问题就自然消失了。

在并发场景下,多个线程同时读一个资源,是不会引发竞态条件的。只有对资源做写操作时才有危险。不可变对象不能被写,所以线程安全

final域能确保初始化过程的安全性,从而可以不受限制地访问不可变对象,并在共享这些对象时无需同步。

正如“除非需要更高的可见性,否则应将所有域都声明为私有域”是一个良好的编程习惯,“除非某个域是可变的,否则将其声明为final域”也是一个良好的编程习惯。

常见的不可变类比如String,是一个常见的面试问题,后面深入学习后再做介绍。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值