2008-10-09 9 views
14

У меня есть большая устаревшая система для обслуживания. Кодовая база использует потоки по всему месту, и эти потоки разделяют множество изменяемых данных. Я знаю, звучит плохо. Во всяком случае, не отвечайте «переписывайте все приложение с нуля» или я проголосую за вас :-) Я попытался запустить некоторые инструменты статического анализа на базе кода, но ни один из них, похоже, не поймает этот случай, который встречается много в нашем исходном коде: несколько потоков - это чтение и запись переменных, которые не помечены как изменчивые или синхронизированные вообще. Обычно это происходит в переменных типа «runFlag». Примером этого является по эффективному Java 2-е издание стр 260:Инструменты для поиска Общедоступные ошибки в Java

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 с «-Server» параметр запуска данной для Sun JVM. Итак, есть ли какой-либо (полуавтоматический) способ найти эти проблемы, или я должен полностью полагаться на обзоры кода?

ответ

1

FindBugs и профессиональные инструменты, основанные на этом, - ваша лучшая надежда, но не рассчитывайте на то, что они найдут все проблемы с параллелизмом в вашем коде.

Если все в этой плохой форме, то вы должны дополнить инструментарий анализом специалистом по параллельному обмену Java.

Это сложная проблема, поскольку окончательно прокладывает. Правильность существующей, но модифицированной базы кода, вероятно, будет нереалистичной - особенно в условиях параллельного использования.

+0

FindBugs не обнаруживает «StopThread» -эксперт выше. – auramo 2008-10-09 12:41:27

2

Последняя версия FindBugs попытается проверить, что поля, помеченные аннотацией @GuardedBy, доступны только в соответствующем защитном коде.

1

Coverity делает некоторые инструменты статического и динамического анализа, которые могут помочь.

http://www.coverity.com/

6

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, найти поле и проверьте, чтобы увидеть, если это летучий.

Проверка на синхронизацию возможна, но может оказаться сложной из-за нескольких условий MONITOREXIT. Прогулки по стопам вызовов тоже могут быть трудными, но тогда это не тривиальная проблема. Однако, я думаю, было бы относительно легко проверить шаблон ошибки, если он будет реализован последовательно.

BCEL выглядит скудно документированным и действительно волосатым, пока не найдете BCELifier класс. Если вы запустите его в классе, он выплевывает Java-источник того, как вы будете строить класс в BCEL.Запуск его на 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(); 
    } 
2

Coverity Analyzer Автор делает работу, но это довольно дорого. IBM Multi-Thread Run-Time Analysis Tool для Java, похоже, способен их обнаруживать, но несколько сложнее настроить. Это инструменты динамического анализа, которые обнаруживают, какие фактические переменные были доступны из разных потоков без правильной синхронизации или волатильности, поэтому результаты более точны, чем при статическом анализе, и могут найти множество проблем, которые статический анализ не может обнаружить.

Если ваш код в основном или, по крайней мере, частично правильно синхронизирован, исправление параллельных проверок FindBugs (или другого статического анализа) также может помочь, по крайней мере, правила IS2_INCONSISTENT_SYNC и UG_SYNC_SET_UNSYNC_GET могут быть хорошими для начала.

 Смежные вопросы

  • Нет связанных вопросов^_^