Java: тестирование доступа потока к “не ориентированные на многопотоковое исполнение” методы

просто удобный способ получить последние n=5 контейнеры (неважно, выполнение или не):

$ docker container ls -a -n5
9
задан amarillion 4 September 2009 в 11:52
поделиться

4 ответа

Спасибо за все советы, вот решение, которое я в итоге придумал. Это оказалось проще, чем я думал. В этом решении используются как AspectJ, так и аннотации. Это работает так: просто добавьте одну из аннотаций (определенных ниже) к методу или классу, и простая проверка на нарушения правил EDT будет вставлена ​​в нее в начале. Если вы помечаете целые классы таким образом, вы можете провести много тестирования с помощью небольшого количества дополнительного кода.

Сначала я загрузил AspectJ и добавил его в свой проект (в eclipse вы можете используйте AJDT )

Затем я определил две новые аннотации:

import java.lang.annotation.ElementType;
import java.lang.annotation.Target;

/**
 * Indicates that this class or method should only be accessed by threads
 * other than the Event Dispatch Thread
 * <p>
 * Add this annotation to methods that perform potentially blocking operations,
 * such as disk, network or database access. 
 */
@Target({ElementType.METHOD, ElementType.TYPE, ElementType.CONSTRUCTOR})
public @interface WorkerThreadOnly {}

и

import java.lang.annotation.ElementType;
import java.lang.annotation.Target;

/**
 * Indicates that this class or method should only be accessed by the 
 * Event Dispatch Thread
 * <p>
 * Add this annotation to methods that call (swing) GUI methods
 */
@Target({ElementType.METHOD, ElementType.TYPE, ElementType.CONSTRUCTOR})
public @interface EventDispatchThreadOnly {}

После этого я определил аспект, который выполняет фактическую проверку:

import javax.swing.SwingUtilities;

/** Check methods / classes marked as WorkerThreadOnly or EventDispatchThreadOnly */
public aspect ThreadChecking {

    /** you can adjust selection to a subset of methods / classes */
    pointcut selection() : execution (* *(..));

    pointcut edt() : selection() && 
        (within (@EventDispatchThreadOnly *) ||
        @annotation(EventDispatchThreadOnly));

    pointcut worker() : selection() && 
        (within (@WorkerThreadOnly *) ||
        @annotation(WorkerThreadOnly));

    before(): edt() {
        assert (SwingUtilities.isEventDispatchThread());
    }

    before(): worker() {
        assert (!SwingUtilities.isEventDispatchThread());
    }
}

Теперь добавьте @EventDispatchThreadOnly или @WorkerThreadOnly к методы или классы, которые должны быть ограничены потоком. Дон' t добавить что-нибудь к потокобезопасным методам.

Наконец, просто запустите с включенными утверждениями (параметр JVM -ea), и вы скоро узнаете, где есть нарушения, если таковые имеются.

Для справки, вот решение Александра Поточкина , на которое ссылался Марк. Это аналогичный подход, но он проверяет вызовы методов Swing из вашего приложения, а не вызовы внутри вашего приложения. Оба подхода дополняют друг друга и могут использоваться вместе.

import javax.swing.*;

aspect EdtRuleChecker {
    private boolean isStressChecking = true;

    public pointcut anySwingMethods(JComponent c):
         target(c) && call(* *(..));

    public pointcut threadSafeMethods():         
         call(* repaint(..)) || 
         call(* revalidate()) ||
         call(* invalidate()) ||
         call(* getListeners(..)) ||
         call(* add*Listener(..)) ||
         call(* remove*Listener(..));

    //calls of any JComponent method, including subclasses
    before(JComponent c): anySwingMethods(c) && 
                          !threadSafeMethods() &&
                          !within(EdtRuleChecker) {
     if(!SwingUtilities.isEventDispatchThread() &&
         (isStressChecking || c.isShowing())) 
     {
             System.err.println(thisJoinPoint.getSourceLocation());
             System.err.println(thisJoinPoint.getSignature());
             System.err.println();
      }
    }

    //calls of any JComponent constructor, including subclasses
    before(): call(JComponent+.new(..)) {
      if (isStressChecking && !SwingUtilities.isEventDispatchThread()) {
          System.err.println(thisJoinPoint.getSourceLocation());
          System.err.println(thisJoinPoint.getSignature() +
                                " *constructor*");
          System.err.println();
      }
    }
}
2
ответ дан 4 December 2019 в 23:40
поделиться

Здесь - запись в блоге с несколькими решениями для проверки нарушений EDT. Один из них - это настраиваемый менеджер перерисовки, а также есть решение AspectJ. Я использовал диспетчер перерисовки в прошлом и нашел его весьма полезным.

2
ответ дан 4 December 2019 в 23:40
поделиться

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

Я бы использовал технологию перехвата.

В наших проектах используется Spring, и мы легко создаем Interceptor, который проверяет это условие перед каждым вызовом. Только во время тестирования мы будем использовать конфигурацию Spring, которая создает перехватчик (мы можем повторно использовать обычную конфигурацию Spring, просто добавив к ней).

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

1
ответ дан 4 December 2019 в 23:40
поделиться

Безусловно, наиболее важным является обеспечение четкого разделения между EDT и не-EDT. Поместите четкую границу между ними. Нет классов ( SwingWorker , я смотрю на вас) с методами в обоих лагерях. Это относится к потокам в целом. Нечетный assert java.awt.EventQueue.isDispatchThread (); хорош рядом с интерфейсами между потоками, но не зацикливайтесь на нем.

1
ответ дан 4 December 2019 в 23:40
поделиться
Другие вопросы по тегам:

Похожие вопросы: