使用注释来监视/记录/报告访问给定方法的线程的java工具?

Ogn*_*yan 12 java multithreading aspectj thread-safety

语境:

我为游戏创建了一个小型(java)多线程服务器.尽管我尽最大努力遵循最佳实践,但事实证明,一些旨在从一个线程调用的方法是从2个或更多线程调用的.经过调试和分析后,我设法"修复"了我的设计,但我想知道:

问题:

是否有一个工具(或者如果不-是有可能(以及如何)开发),它允许您标记一些方法中包含注释@SingleThread@ThreadCount(2)@ThreadNameLike("my_fancy_thread_group*")用于计数/监视/日志访问这些方法,如:

  • @SingleThread - 检查此方法是否始终仅由线程访问
  • @ThreadCount(2) - 完全由两个线程访问
  • @ThreadNameLike - 仅由名称与模式匹配的线程访问

我们的想法是对程序进行TEST运行,并至少获得违反注释条件的日志记录.

我当时认为可能AspectJ可以通过它的切入点来完成这项工作但后来我意识到类似于Dagger/Dagger2的方法会更好,即当你想测试你的服务器时你必须打开一个注释处理器(让我们假设它称为"SafetyFirst",它将生成包含监视代码的适配器(包装器?)类.然后,您将运行服务器,运行一些负载测试,然后检查日志是否存在违规(或在理想的世界中 - 获取报告文件).

我完全意识到这样的工具:

  • 不会对所有潜在案件提供100%的报道;
  • 将掩盖/触发heisenbugs
  • 将减慢检查的程序

但至少它可以作为一个早期预警系统,清楚地宣传违反预期设计的行为.

hsn*_*rmn 5

我使用了类似的AspectJ加载时间编织测试来打算在我的包中打印所有函数调用.

加载时间编织的最佳方法是你不要像编译时间那样弄脏你的类.-javaagent:<path to aspectj lib>从运行命令中删除自定义的自定义lib类路径条目时.然后一切都消失了,清楚.

我做了一些更改,并实施了一个涵盖你问的@ThreadCount功能的测试.您需要下载并安装AspectJ.

请参阅代码段:

aspect Profile {

    private static Map<String, AtomicInteger> counterMap = new HashMap<String, AtomicInteger>();

    pointcut threadCountPc(test.ThreadCount tc) : execution(* test..*(..)) && @annotation(tc);

    Object around(test.ThreadCount tc) : threadCountPc(tc) {        

        String signature = thisJoinPointStaticPart.getSignature().toString();

        AtomicInteger counter = getCounter(signature);
        int currentValue = counter.incrementAndGet();

        if (currentValue >= tc.value()){
            System.out.println("[Thread Name:" + Thread.currentThread().getName() + 
            "] Method Name:" + signature + ", threadCount:" + currentValue + " exceeds " + tc.value());
        }

        try{
            return proceed(tc);
        }finally{
            counter.decrementAndGet();          
        }
    }

    private static AtomicInteger getCounter(String methodName){
        AtomicInteger value = counterMap.get(methodName);
        if (value == null){
            synchronized (counterMap){
                value = counterMap.get(methodName);
                if (value == null){
                    value = new AtomicInteger(0);
                    counterMap.put(methodName, value);
                }
            }
        }
        return value;
    }
}
Run Code Online (Sandbox Code Playgroud)

编译: "C:/aspectj1.8/bin/ajc.bat" profile_ft.aj -cp C:/aspectj1.8/lib/aspectjrt.jar;../test/. -1.6 -outxml -outjar profile_ft.jar

运行: java -javaagent:C:/aspectj1.8/lib/aspectjweaver.jar -cp aspectj/profile_ft.jar;test test.Test1