gpt4 book ai didi

java - 破解并发代码

转载 作者:塔克拉玛干 更新时间:2023-11-02 07:47:08 26 4
gpt4 key购买 nike

假设我有以下类(class):

public class BuggyClass {

private String failField = null;

public void create() {
destroy();
synchronized (this) {
failField = new String("Ou! la la!");
}
}

public void destroy() {
synchronized (this) {
failField = null;
}
}

public long somethingElse() {
if (failField == null) {
return -1;
}
return failField.length();
}

}

很容易看出,在以上代码的多线程执行中,我们可以在somethingElse 中得到一个NullPointerExeption。例如,它可能是 failField != null 并且在返回之前 failField.length() destroy 被调用因此使得 failFieldnull

我想创建一个多线程程序,在使用 BuggyClass 时能够“抛出”一个 NullPointerException。我知道,由于该程序是多线程的,所以这可能永远不会发生,但我想应该有一些更好的测试来增加出现异常的可能性。对吧?

我尝试了以下方法:

final BuggyClass bc = new BuggyClass();
final int NUM_OF_INV = 10000000;
int NUM_OF_THREADS = 5;
ExecutorService executor = Executors.newFixedThreadPool(3 * NUM_OF_THREADS);

for (int i = 0; i < (NUM_OF_THREADS); ++i) {
executor.submit(new Runnable() {
public void run() {
for(int i = 0; i< NUM_OF_INV; i++){
bc.create();
}
}
});
}


for (int i = 0; i < (NUM_OF_THREADS); ++i) {
executor.submit(new Runnable() {
public void run() {
for(int i = 0; i< NUM_OF_INV; i++){
bc.destroy();
}}
});
}

for (int i = 0; i < (NUM_OF_THREADS); ++i) {
executor.submit(new Runnable() {
public void run() {
for(int i = 0; i< NUM_OF_INV; i++){
bc.somethingElse();
}}
});
}
executor.shutdown(); executor.awaitTermination(1, TimeUnit.DAYS);

我使用不同的 NUM_OF_INVNUM_OF_THREADS 多次执行上述代码(方法),但从未设法获得 NullPointerException

关于如何创建一个测试增加我在不更改 BuggyClass 的情况下获得异常的机会的任何想法?

最佳答案

虽然您的代码中存在数据竞争,但可能无法发现任何由此数据竞争 引起的问题。最有可能的是,JIT 编译器会将方法 somethingElse 转换成如下所示:

public long somethingElse() {
String reg = failField; // load failField into a CPU register
if (reg == null) {
return -1;
}
return reg.length();
}

这意味着,编译器不会在条件之后加载引用failField。并且不可能触发NullPointerException


更新:我用 GCJ 编译了方法 somethingElse 以查看一些真实的和优化的汇编器输出。它看起来如下:

long long BuggyClass::somethingElse():
movq 8(%rdi), %rdi
testq %rdi, %rdi
je .L14
subq $8, %rsp
call int java::lang::String::length()
cltq
addq $8, %rsp
ret
.L14:
movq $-1, %rax
ret

您可以从这段代码中看到,引用failField 被加载了一次。当然,不能保证所有的实现现在和永远都使用相同的优化。所以,您不应该依赖它。

关于java - 破解并发代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23119711/

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