【发布时间】:2014-12-28 06:59:17
【问题描述】:
问题已发布before,但没有提供有效的实际示例。所以 Brian 提到在某些情况下 AssertionError 可能出现在以下代码中:
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");
}
}
当持有人被这样不当发布时:
class someClass {
public Holder holder;
public void initialize() {
holder = new Holder(42);
}
}
我知道,当对 holder 的引用在对象持有者的实例变量对另一个线程可见之前变得可见时,会发生这种情况。所以我做了下面的例子来引发这种行为,从而引发带有以下类的 AssertionError:
public class Publish {
public Holder holder;
public void initialize() {
holder = new Holder(42);
}
public static void main(String[] args) {
Publish publish = new Publish();
Thread t1 = new Thread(new Runnable() {
public void run() {
for(int i = 0; i < Integer.MAX_VALUE; i++) {
publish.initialize();
}
System.out.println("initialize thread finished");
}
});
Thread t2 = new Thread(new Runnable() {
public void run() {
int nullPointerHits = 0;
int assertionErrors = 0;
while(t1.isAlive()) {
try {
publish.holder.assertSanity();
} catch(NullPointerException exc) {
nullPointerHits++;
} catch(AssertionError err) {
assertionErrors ++;
}
}
System.out.println("Nullpointerhits: " + nullPointerHits);
System.out.println("Assertion errors: " + assertionErrors);
}
});
t1.start();
t2.start();
}
}
无论我运行多少次代码,AssertionError 都不会发生。所以对我来说有几个选择:
- jvm 实现(在我的例子中是 Oracle 的 1.8.0.20)强制在对象构造期间设置的不变量对所有线程都是可见的。
- 这本书是错的,我会怀疑作者是 Brian Goetz ... nuf 说
- 我在上面的代码中做错了
所以我的问题是: - 有人成功挑起过这种 AssertionError 吗?那用什么代码呢? - 为什么我的代码没有引发 AssertionError?
【问题讨论】:
-
@SotiriosDelimanolis作者在书中所说的是两个线程可能会看到不同状态的Holder对象,所以在一个线程的Object类中n可能会被初始化为0。
-
为什么要推迟
t2的启动? -
该代码的历史原因。我也曾经循环直到 t2 的最大整数,而不是寻找 t1.isAlive()。因为 t2 的执行速度非常快,所以它可以在 t1 没有做任何有用的事情之前完成。但好吧,现在它不再需要了。
-
我回来是因为我看到了this post
-
很好的例子@grape_mao(谢谢),我也会试试那个例子。想知道我是否可以将其仅适应一个变量而不是两个变量,这肯定也会产生影响。
标签: java concurrency thread-safety