【问题标题】:When implementing threads, is it better to use immutable objects over mutable ones?在实现线程时,使用不可变对象而不是可变对象更好吗?
【发布时间】:2013-10-09 16:33:46
【问题描述】:

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

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

If immutable objects are good, why do people keep creating mutable objects? (Programmers.SE)

对于大型和/或复杂的对象,为每次更改创建对象的新副本可能会非常昂贵和/或乏味。对于具有不同身份的对象,更改现有对象比创建新的修改副本要简单和直观得多。

Immutable Objects(Java 教程)

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

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

【问题讨论】:

  • 是的,但是线程安全仍然很难。请参阅我的博客,blog.slaks.net/2013-07-22/thread-safe-data-structures
  • 不幸的是,这个问题主要是基于意见的,当然取决于您的应用程序的具体情况。有时您想使用不可变对象,而有时这是不可能的。
  • 你相信自己吗?还有谁会在代码中胡闹?

标签: java multithreading thread-safety


【解决方案1】:

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

一般来说,只要可行,我都会尝试使具有简单字段的对象不可变,并且我发现从不可变对象最安全的默认设置开始并仅在有特定原因需要它们时才使用突变器是很有帮助的。

同样,如果您要依赖类的不变性来实现线程安全,通常应该声明类final 以避免各种麻烦。我并没有坚持所有类都必须是abstractfinal,但final 可实例化类是一个很好的默认值。

【讨论】:

    【解决方案2】:

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

    有几个大优点:

    • 线程安全。如果你不能改变它的状态,那么两个线程就不可能同时更新它或看到它的不同版本。

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

    • 可以是单例。由于该对象是线程安全的,因此无需为单独的线程提供它们自己的版本。您可以将它传递给多个线程,因为您知道状态不会改变,从而避免您可能不得不花费更多的内存来创建副本。

    【讨论】:

      【解决方案3】:

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

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

      您可能应该研究 ACID: http://en.wikipedia.org/wiki/ACID

      Java 还具有可靠且易于实现的同步代码方法,因此可以从多个线程安全地访问可变对象。对于需要在内存消耗方面具有高性能的系统,这可能是要走的路。但同样,这是基于您的限制的权衡 - 内存或速度哪个更重要?

      【讨论】:

        【解决方案4】:

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

        不可变对象只是掩盖了这种复杂性——我现在必须保证我持有的引用对象不是陈旧的。此外,如果我拥有的版本确实过时,我现在必须确定该对象的最新版本在哪里。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-02-04
          • 2015-12-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多