使用 clone() 和非 final 字段的流利类的线程安全 [英] Thread safety of a fluent like class using clone() and non final fields

查看:17
本文介绍了使用 clone() 和非 final 字段的流利类的线程安全的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

This fluent like class is not strictly immutable because the fields are not final, but is it thread safe, and why?

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

The thread safety issue I'm concerned with is not the race condition, but the visibility of the variables. I know there is a workaround using final variables and a constructor instead of clone() + assignment. I just want to know if this example is a viable alternative.

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);
        }
    }
}

推荐答案

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

You are not holding a Lock while setting the field and as you mention yourself the field is not final.

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

Therefore from a visibility standpoint this approach is not thread-safe.

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

Some further clarifications here: https://stackoverflow.com/a/9633968/136247

关于使用 volatile 的问题的更新:

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

For the sake of the argument using volatile fixes the threading issue here.
However you should reconsider final fields and a copy constructor because:

  • 字段访问会稍微快一点(读取总是来自 cpu 缓存)
  • 避免不鼓励使用 clone(请参阅 Josh Bloch 的 Effective Java)
  • 具有 final 字段的构造函数是不可变类的已知习语,代码的读者很容易识别
  • 标记字段 volatile 而打算使它们不可变本身就是一个矛盾;)
  • Field access will be slightly faster (the reads can always come from the cpu cache)
  • You avoid the discouraged use of clone (see Effective Java by Josh Bloch)
  • Constructor with final fields is a known idiom for immutable classes and will be easily recognised by readers of the code
  • Marking fields volatile while intending for them to be immutable is a contradiction in and of itself ;)

这篇关于使用 clone() 和非 final 字段的流利类的线程安全的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆