【发布时间】:2021-06-13 13:28:03
【问题描述】:
在 Java Concurrency In Practice 一书中,有一个几乎不可变对象的示例,如果没有正确发布,它就有失败的风险:
// 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);
}
}
如果我正确理解书中的章节,将final 添加到Holder 类的n 字段将使对象完全不可变,并且即使AssertionError 仍然存在,也不会被抛出在没有充分同步的情况下发布,就像在 Client 类中所做的那样。
现在我想知道匿名类在这方面的表现如何。请看下面的例子:
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 类已成为一个接口,并且有一个静态工厂方法返回一个实现该接口的匿名类,而匿名类使用方法参数n。
我的问题是:有没有机会从我的后一个示例中获得AssertionError?如果有,使其完全不可变并消除问题的最佳方法是什么?如果它以如下的函数方式编写,它会改变什么吗?
class IHolderFactory {
static IHolder create(int n) {
return () -> {
if (n != n)
throw new AssertionError("This statement is false.");
};
}
}
【问题讨论】:
标签: java multithreading concurrency language-lawyer