当前位置:  开发笔记 > 编程语言 > 正文

用于在Java中查找Shared Mutable数据错误的工具

如何解决《用于在Java中查找SharedMutable数据错误的工具》经验,为你挑选了1个好方法。

我有一个庞大的遗留系统来维护.代码库使用遍布各处的线程,这些线程共享大量可变数据.我知道,听起来很糟糕.无论如何,不​​回答"从头开始重写整个应用程序"或者我会投票给你:-)我试图在代码库上运行一些静态分析工具,但这些似乎都没有抓住这种情况发生了很多在我们的源代码中:多个线程正在读取和写入未标记为volatile或同步的变量.通常这发生在"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"启动参数.那么,是否有任何(半)自动方式来查找这些问题,或者我是否必须完全依赖代码审查?



1> McDowell..:

Chris Grindstaff撰写了一篇文章FindBugs,第2部分:编写自定义检测器,其中描述了如何使用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:
==========================
method:run
static access:access$0
      on type:StopThread

然后可以扫描StopThread类型,找到该字段并检查它是否是易失性的.

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

在您找到BCELifier类之前,BCEL看起来很难记录并且非常毛茸茸.如果你在一个类上运行它,它会向你发出如何在BCEL中构建类的Java源代码.在StopThread上运行它可以生成访问$ 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();
  }

推荐阅读
k78283381
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有