繁体   English   中英

在实现线程时,使用不可变对象比使用可变对象更好吗?

[英]When implementing threads, is it better to use immutable objects over mutable ones?

我目前正在学习java中的线程,从我所读到的,实现它们不是问题,而是使代码线程安全。 这让我想到了一个问题:我应该尽可能使用不可变对象来确保防止并发错误吗?

我已经阅读了关于何时使用可变对象的不同意见,包括:

如果不可变对象是好的,为什么人们一直在创建可变对象? (Programmers.SE)

对于大型和/或复杂对象,为每个单独的改变创建对象的新副本可能是非常昂贵和/或繁琐的。 对于具有不同身份的对象,更改现有对象比创建新的已修改副本更加简单直观。

不可变对象 (Java教程)

对象创建的影响经常被高估,并且可以通过与不可变对象相关联的一些效率来抵消。 这些包括由于垃圾收集而减少的开销,以及消除保护可变对象免于损坏所需的代码。

那么,实现线程时是否有最佳实践? 我应该尽可能尝试使用不可变对象吗?

使用真正不可变的对象(没有包含对可变类的引用的字段)是线程安全的,并且在实际使用时使用它们是一个好习惯,但是不可变性是否可行取决于具体情况; 例如,某些工具包需要setter或field injection,因此不能与不可变对象一起使用。 使用Value Object模式,Immutability通常是最实用的,其中对象没有任何特别复杂的行为,并且基本上封装了一个清晰可描述的值( String ,原始包装器,Guava的Immutable*集合)。

一般来说,我尝试在实际的情况下使用简单的字段使对象变得不可变,并且我发现从默认情况开始,不可变对象是最安全的,并且只有在需要它们的特定原因时才使用mutators是有帮助的。

类似地,如果你要依赖类的不变性来做线程安全之类的东西,你通常应该声明类final以避免各种令人头疼的问题。 我并没有坚持所有类都必须是abstractfinal ,但final实例化的类是一个很好的默认。

是的,当多线程时,不可变对象通常是你的朋友。

有一些很大的优点:

  • 线程安全的。 如果您无法更改它的状态,那么两个线程无法同时更新它或查看它的单独版本。

  • 没有锁定。 因为没有任何变化,所以不需要使用synchronized关键字。 这为您提供了性能奖励和简单性。

  • 可以是单身人士。 由于该对象是线程安全的,因此不需要为它们自己的版本提供单独的线程。 您可以将其传递给多个线程,因为它们知道状态不会发生变化,从而使您不必花费更多内存来创建副本。

我认为这实际上取决于你将使用它们的背景。 它是一个将在多个线程中不断访问的对象吗? 系统的硬件限制是什么?

它不是关于对象是不可变的还是可变的,而是关于它们如何被访问。 即使是不可变对象,如果在访问副本的同时复制它也会导致线程安全问题...

您应该查看ACID: http//en.wikipedia.org/wiki/ACID

Java还具有可靠且易于实现的同步代码的方法,以便可以从多个线程安全地访问可变对象。 对于需要在内存消耗方面具有高性能的系统,这可能是最佳选择。 但同样,这是基于你的限制 - 一个更重要的记忆或速度的折衷?

线程访问对象的问题始终是安全地更改对象; 如果可以保证状态不会同时被更改,则读取对象的状态本质上是安全的。 (显然我的回答是假设您正在使用线程代码更改对象。)

不可变对象简单地掩盖了这种复杂性 - 我现在必须保证我持有引用的对象不是陈旧的。 另外,我现在必须确定该对象的最新版本在哪里,如果我的版本确实是陈旧的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM