Ma stratégie pour les problèmes de filetage dans une application Java Swing est de diviser les méthodes en trois types: p>
Je pense que c'est une approche valide pour les applications GUI, où il n'y a généralement que deux threads. Couper le problème aide vraiment à réduire la "surface de la surface" pour les conditions de course. La mise en garde bien sûr est que vous n'appelez jamais accidentellement une méthode du mauvais fil. P>
Ma question concerne les tests: P>
Y a-t-il des outils de test qui peuvent m'aider à vérifier qu'une méthode est appelée depuis le bon fil? Je sais sur swingutieux.isEventDisPatTthread () code>, mais je cherche vraiment quelque chose à l'aide d'annotations Java ou de programmation orientée de l'aspect afin que je n'ai pas besoin d'insérer le même code de la chaudière dans chaque méthode du programme. p>
4 Réponses :
De ce que j'ai lu, vous avez déjà une solution spécifique, vous ne souhaitez que réduire le code de la chaudière requis. P>
J'utiliserais une technologie d'interception. P>
Nos projets utilisent le ressort et nous créons facilement un intercepteur qui vérifie cette condition avant chaque appel. Au cours des tests - uniquement, nous utiliserions une configuration de printemps qui crée un intercepteur (nous pouvons réutiliser la configuration Spring régulière, simplement l'ajouter). P>
Pour savoir quel cas nous devrions utiliser pour une méthode, vous pouvez lire l'annotation par exemple ou utiliser une autre moyenne de configuration. P>
ici est une entrée de blog avec un Peu de solutions pour vérifier les violations de l'EDT. L'un est un gestionnaire de Repeaker personnalisé et il y a aussi une solution de AspectJ. J'ai utilisé le gestionnaire Repeaker dans le passé et j'ai trouvé cela assez utile. P>
De loin la chose la plus importante à faire est de veiller à ce qu'il existe une séparation claire entre EDT et Non-EDT. Mettre une interface claire entre les deux. Ne pas avoir de cours ( swingworker code>, je vous regarde) avec des méthodes dans les deux camps. Cela s'applique aux threads en général. L'impair
affirme java.awt.eventqueue.isdispatterthread (); code> est agréable près des interfaces entre les threads, mais ne vous accrochez pas dessus. p>
Merci pour tous les conseils, voici la solution que j'ai proposée à la fin. C'était plus facile que je pensais. Cette solution utilise à la fois Aspecj et Annotations. Cela fonctionne comme ceci: ajoutez simplement l'une des annotations (définie ci-dessous) à une méthode ou une classe, et une simple vérification des violations de la règle EDT sera insérée au début. Surtout si vous marquez des classes entières comme celle-ci, vous pouvez faire beaucoup de tests avec une petite quantité de code supplémentaire.
J'ai d'abord téléchargé aspressj et l'a ajouté à mon projet (dans Eclipse, vous pouvez utiliser AJDT ) p>
Puis j'ai défini deux nouvelles annotations: p> et p> Après cela, j'ai défini l'aspect qui fait la vérification réelle: p> ajoutez maintenant @eventdispatthreadonly ou @workerThreadonly aux méthodes ou aux classes qui doivent être enfermées. N'ajoutez rien aux méthodes de sécurité. P> Enfin, il vous suffit de fonctionner avec des assertions activées (JVM Option -Aea) et vous le découvrirez assez rapidement lorsque les violations sont, le cas échéant. P> À des fins de référence, voici la solution de Alexander Potochkin , quelle marque a été mentionnée. C'est une approche similaire, mais elle vérifie les appels pour balancer des méthodes de votre application, au lieu d'appels dans votre application. Les deux approches sont complémentaires et peuvent être utilisées ensemble. P> 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();
}
}
}
+1 pour la question créative
synchronisé n'est pas égal à la sécurité du fil. Je vous suggère fortement de lire les «nouvelles» libs de simultanéité de Java 5, en particulier les contrats à terme semblent être utiles pour le développement de swing, je pense.
@Jens: Vous avez raison, j'ai légèrement modifié la question.