gpt4 book ai didi

java - 在 Java 中查找共享可变数据错误的工具

转载 作者:搜寻专家 更新时间:2023-10-30 19:44:44 26 4
gpt4 key购买 nike

我有一个大型遗留系统需要维护。代码库到处都使用线程,这些线程共享大量可变数据。我知道,听起来很糟糕。无论如何,不​​要回答“从头开始重写整个应用程序”,否则我会否决你:-)在我们的源代码中:多个线程正在读写变量,这些变量根本没有标记为 volatile 或 synchronized。通常这发生在“runFlag”类型的变量上。 Effective Java 第 2 版第 260 页就是一个例子:

public class StopThread
{
private static boolean stopRequested;
public static void main(String[] args) throws InterruptedException
{
Thread backgroundThread = new Thread(new Runnable()
{
public void run()
{
int i = 0;
while (!stopRequested)
{
i++;
}
}
});
backgroundThread.start();
Thread.sleep(1000);
stopRequested = true;
}
}

此示例在 Windows/Linux 上永远不会完成,并向 Sun JVM 提供“-server”启动参数。那么,是否有任何(半)自动的方法来发现这些问题,或者我是否必须完全依赖代码审查?

最佳答案

Chris Grindstaff 写了一篇文章 FindBugs, Part 2: Writing custom detectors他在其中描述了如何使用 BCEL添加您自己的规则。 (BCEL 不是唯一的字节码库——但它是 FindBugs 使用的库。)

下面的代码给出了方法访问静态方法或字段的任何情况。您可以在任何实现Runnable 的类型上运行它。

public class StaticInvocationFinder extends EmptyVisitor {

@Override
public void visitMethod(Method obj) {
System.out.println("==========================");
System.out.println("method:" + obj.getName());

Code code = obj.getCode();
InstructionList instructions = new InstructionList(code.getCode());
for (Instruction instruction : instructions.getInstructions()) {
// static field or method
if (Constants.INVOKESTATIC == instruction.getOpcode()) {
if (instruction instanceof InvokeInstruction) {
InvokeInstruction invokeInstruction = (InvokeInstruction) instruction;
ConstantPoolGen cpg = new ConstantPoolGen(obj
.getConstantPool());
System.out.println("static access:"
+ invokeInstruction.getMethodName(cpg));
System.out.println(" on type:"
+ invokeInstruction.getReferenceType(cpg));
}
}
}
instructions.dispose();
}

public static void main(String[] args) throws Exception {
JavaClass javaClass = Repository.lookupClass("StopThread$1");

StaticInvocationFinder visitor = new StaticInvocationFinder();
DescendingVisitor classWalker = new DescendingVisitor(javaClass,
visitor);
classWalker.visit();
}

}

此代码发出以下内容:

==========================
method:<init>
==========================
method:run
static access:access$0
on type:StopThread

然后可以扫描 StopThread 类型,找到该字段并检查它是否是 volatile

检查同步是可能的,但由于多个 MONITOREXIT 条件可能会变得棘手。遍历调用堆栈也可能很困难,但这不是一个小问题。但是,我认为如果一致实现,检查错误模式会相对容易。

在您找到 BCELifier 类之前,BCEL 看起来几乎没有文档,而且真的很毛茸茸。如果你在一个类上运行它,它会吐出你将如何在 BCEL 中构建类的 Java 源代码。在 StopThread 上运行它可以生成 access$0 合成访问器:

  private void createMethod_2() {
InstructionList il = new InstructionList();
MethodGen method = new MethodGen(ACC_STATIC | ACC_SYNTHETIC, Type.BOOLEAN, Type.NO_ARGS, new String[] { }, "access$0", "StopThread", il, _cp);

InstructionHandle ih_0 = il.append(_factory.createFieldAccess("StopThread", "stopRequested", Type.BOOLEAN, Constants.GETSTATIC));
il.append(_factory.createReturn(Type.INT));
method.setMaxStack();
method.setMaxLocals();
_cg.addMethod(method.getMethod());
il.dispose();
}

关于java - 在 Java 中查找共享可变数据错误的工具,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/187004/

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