gpt4 book ai didi

java - 匿名类可以完全不可变吗?

转载 作者:行者123 更新时间:2023-12-03 12:44:06 25 4
gpt4 key购买 nike

在 Java Concurrency In Practice 一书中,有一个几乎不可变对象(immutable对象)的示例,如果没有正确发布,就有失败的风险:

// Taken from Java Concurrency In Practice
// p.51 Listing 3.15: Class at risk of failure if not properly published.
public class Holder {
private int n;

public Holder(int n) { this.n = n; }

public void assertSanity() {
if(n != n)
throw new AssertionError("This statement is false.");
}
}

// p.50 Listing 3.14: Publishing an object without adequate synchronization. Don't do this.
class Client {
public Holder holder;

public void initialize() {
holder = new Holder(42);
}
}
如果我正确理解书中的章节,添加 finaln Holder 的字段类将使对象完全不可变并消除获得 AssertionError 的机会即使它仍然在没有足够同步的情况下发布,就像它在 Client 中所做的那样,也会被抛出。类(class)。
现在我想知道匿名类在这方面的表现如何。请看下面的例子:
public interface IHolder {
void assertSanity();
}

class IHolderFactory {
static IHolder create(int n) {
return new IHolder() {
@Override
public void assertSanity() {
if (n != n)
throw new AssertionError("This statement is false.");
}
};
}
}

class IHolderClient {
public IHolder holder;

public void initialize() {
// is this safe?
holder = IHolderFactory.create(42);
}
}
就像书中的示例一样,它在没有充分同步的情况下发布,但不同之处在于现在 Holder类变成了接口(interface),有一个静态工厂方法返回实现接口(interface)的匿名类,匿名类使用方法参数 n .
我的问题是:是否有机会获得 AssertionError从我的后一个例子抛出?如果有,使其完全不可变并消除问题的最佳方法是什么?如果它是以如下的功能方式编写的,它会改变什么吗?
class IHolderFactory {
static IHolder create(int n) {
return () -> {
if (n != n)
throw new AssertionError("This statement is false.");
};
}
}

最佳答案

这是一个非常棘手的问题。
JLS, §17.4.1. Shared Variables说:

Local variables (§14.4), formal method parameters (§8.4.1), and exception handler parameters (§14.20) are never shared between threads and are unaffected by the memory model.


这似乎与您可以在可以在线程之间共享的内部类或 lambda 表达式中使用它们的事实相矛盾,但是这些构造捕获变量的值并使用该值。然而,这个过程并没有很好地说明。
我能找到的唯一提及是在 §15.27.2解释(有效的)最终要求:

The restriction to effectively final variables prohibits access to dynamically-changing local variables, whose capture would likely introduce concurrency problems.


在实践中,捕获的值存储在合成 final 中。内部类或在运行时为 lambda 表达式生成的类的字段。因此,您将永远不会看到当前实现的错误。
然而,这并没有在任何地方指定。语言规范说 little about the bytecode format并且虚拟机规范对语言结构几乎没有说明。
因此,局部变量、形式方法参数和异常处理程序参数被明确排除在 JMM 之外,它们捕获的值在 JMM 方面不是变量,甚至没有被提及。问题是这意味着什么。
它们通常不受数据竞争的影响(我的解释)还是它们不安全并且我们根本没有从 JMM 那里得到任何保证?在后一种情况下,它甚至暗示我们无法保证它们的安全,因为任何安全的发布机制都可以从不包括我们的情况的 JMM 保证中获得安全性。值得注意的是,JMM 也没有覆盖外部 this引用也不是实例对 Class 的隐式引用 getClass() 返回的对象.
因此,虽然我认为它们不受数据竞争的影响,但我希望能更明确地说明这一点。

关于java - 匿名类可以完全不可变吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66652250/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com