java - 使用clone()和非final字段的流畅类的线程安全

标签 java thread-safety fluent-interface

这个像流利的类并不是严格不可变的,因为字段不是最终的,但它是线程安全的,为什么?

我关心的线程安全问题不是竞争条件,而是变量的可见性。我知道有一种解决方法,使用最终变量和构造函数而不是克隆()+赋值。我只是想知道这个例子是否是一个可行的替代方案。

public class IsItSafe implements Cloneable {

    private int foo;
    private int bar;

    public IsItSafe foo(int foo) {
        IsItSafe clone = clone();
        clone.foo = foo;
        return clone;
    }

    public IsItSafe bar(int bar) {
        IsItSafe clone = clone();
        clone.bar = bar;
        return clone;
    }

    public int getFoo() {
        return foo;
    }

    public int getBar() {
        return bar;
    }

    protected IsItSafe clone() {
        try {
            return (IsItSafe) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new Error(e);
        }
    }
}

最佳答案

您在设置字段时没有持有锁,并且正如您提到的那样,该字段不是最终的。

因此,从可见性的角度来看,这种方法不是线程安全的。

这里有一些进一步的说明:https://stackoverflow.com/a/9633968/136247

有关使用 volatile 问题的更新:

为了论证,使用 volatile 修复了这里的线程问题。
但是,您应该重新考虑最终字段和复制构造函数,因为:

  • 字段访问会稍微快一些(读取始终可以来自 CPU 缓存)
  • 避免不鼓励使用克隆(请参阅 Josh Bloch 的《Effective Java》)
  • 具有 Final 字段的构造函数是不可变类的已知惯用法,代码读者很容易识别
  • 将字段标记为 volatile ,同时希望它们不可变,这本身就是一个矛盾;)

关于java - 使用clone()和非final字段的流畅类的线程安全,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9621260/

相关文章:

api - Fluent API 与其他 API 有何不同?

.net - 依赖注入(inject)和 Fluent APIs——遇到了一些问题

c# - 设计流畅的界面方法

java - LibGDX "GwtApplication: exception: Couldn' t 加载图像 'a.jpg'

java - 帮助需要从 HashMap 创建哈希集

ios - UITableView reloadData 在 iOS 11 中重新出现时崩溃

java - 数组在 Java 中是线程安全的吗?

c - 互斥量应该存储在 main 中还是对象中?

java - 在 Java 中使用 volatile 集合和数组

java - 获取 JPA 和 Hibernate 继承树中的鉴别器值列表