2011-12-16 1 views
4

Nous savons tous que nous devons faire toutes les tâches liées à l'interface graphique du thread de répartition des événements et que les bugs étranges peuvent être introduits autrement - j'essaie de se rappeler cette règle, mais je dois admettre que je l'ai remarqué deux ou trois endroits récemment où je n'ai pas.Trouver des violations de fil d'expédition des événements

Existe-t-il un moyen d'identifier toutes les violations de cette règle afin qu'elles puissent être corrigées? J'ai vu qu'il y a une règle de findbugs pertinente here mais il ne semble pas attraper tous les cas pour moi. Même lancer une exception chaque fois qu'une violation se produit serait agréable afin que je puisse le réparer (ou attraper l'exception et enregistrer l'avertissement dans le cas où un utilisateur rencontre un problème connexe.)

Quelles sont les approches généralement adoptées par les utilisateurs?

+2

Voir aussi ce lié [Q & A] (http://stackoverflow.com/questions/7787998/how-to-generate-exceptions-from-repaintmanager). – trashgod

Répondre

5

Une approche consiste à installer un gestionnaire de repeindre personnalisé qui détecte et journaux lorsque la peinture est effectuée sur un fil autre que l'EDT. Nous utilisons cette approche sur notre projet, adapté du blog suivant: http://weblogs.java.net/blog/alexfromsun/archive/2006/02/debugging_swing.html. Cela ne détectera pas toutes les classes de violations de threads EDT, mais c'est nettement mieux que rien.

Mise à jour:

Comme un commentateur a fait remarquer, la page Web liée est plus disponible. Voici mon code adapté de l'affichage de blog:

import javax.swing.JComponent; 
import javax.swing.RepaintManager; 
import javax.swing.SwingUtilities; 
import org.apache.log4j.Logger; 
import sun.awt.AppContext; 

public class DetectEdtViolationRepaintManager extends RepaintManager { 

    private static final Logger LOGGER = Logger.getLogger(
    DetectEdtViolationRepaintManager.class); 

    /** 
    * Used to ensure we only print a stack trace once per abusing thread. May 
    * be null if the option is disabled. 
    */ 
    private ThreadLocal alreadyWarnedLocal; 

    /** 
    * Installs a new instance of DetectEdtViolationRepaintManager which does not 
    * warn repeatedly, as the current repaint manager. 
    */ 
    public static void install() { 
    install(false); 
    } 

    /** 
    * Installs a new instance of DetectEdtViolationRepaintManager as the current 
    * repaint manager. 
    * @param warnRepeatedly whether multiple warnings should be logged for each 
    *  violating thread 
    */ 
    public static void install(boolean warnRepeatedly) { 
    AppContext.getAppContext().put(RepaintManager.class, 
     new DetectEdtViolationRepaintManager(warnRepeatedly)); 
    LOGGER.info("Installed new DetectEdtViolationRepaintManager"); 
    } 

    /** 
    * Creates a new instance of DetectEdtViolationRepaintManager. 
    * @param warnRepeatedly whether multiple warnings should be logged for each 
    *  violating thread 
    */ 
    private DetectEdtViolationRepaintManager(boolean warnRepeatedly) { 
    if (!warnRepeatedly) { 
     this.alreadyWarnedLocal = new ThreadLocal(); 
    } 
    } 

    /** 
    * {@inheritDoc} 
    */ 
    public synchronized void addInvalidComponent(JComponent component) { 
    checkThreadViolations(); 
    super.addInvalidComponent(component); 
    } 

    /** 
    * {@inheritDoc} 
    */ 
    public synchronized void addDirtyRegion(JComponent component, int x, int y, 
    int w, int h) { 
    checkThreadViolations(); 
    super.addDirtyRegion(component, x, y, w, h); 
    } 

    /** 
    * Checks if the calling thread is called in the event dispatch thread. 
    * If not an exception will be printed to the console. 
    */ 
    private void checkThreadViolations() { 
    if (alreadyWarnedLocal != null && Boolean.TRUE.equals(alreadyWarnedLocal.get())) { 
     return; 
    } 
    if (!SwingUtilities.isEventDispatchThread()) { 
     if (alreadyWarnedLocal != null) { 
     alreadyWarnedLocal.set(Boolean.TRUE); 
     } 
     LOGGER.warn("painting on non-EDT thread", new Exception()); 
    } 
    } 
} 
+0

Merci, c'est vraiment prometteur - je vais jeter un coup d'oeil! – berry120

+0

le lien ne fonctionne plus. avez-vous la nouvelle adresse? – peterboston

4

J'essaie juste d'être prudent, moi-même. Mais vous pouvez installer du code pour tester si un morceau donné de code s'exécute dans le thread d'envoi avec SwingUtilities.isEventDispatchThread(), et faites ce que vous voulez s'il ne l'est pas (ou si c'est le cas).

3

Le Substance Look and Feel comprend un runtime EDT violation checker automatique. Il peut aider à détecter les violations EDT lors des tests. Il lance une exception IllegalStateException lorsqu'une violation est détectée. C'est bon pour les tests.

+0

convenu, mes mots +1 – mKorbel

+0

avez-vous une idée de comment obtenir le vérificateur de violation EDT (seulement) de son github? – peterboston

0

Fest's swing module comprend également un EDT violtion checker vous pouvez installer, ce qui jette une exception lorsqu'il détecte une violation.

+0

avez-vous la nouvelle adresse sur le vérificateur de violation EDT? L'ancien ne fonctionne plus. – peterboston

Questions connexes