Question

J'ai une application swing qui stocke une liste d'objets. Lorsque les utilisateurs clique sur un bouton,

Je veux effectuer deux opérations sur chaque objet dans la liste, puis une fois que terminée, graphique les résultats dans un JPanel. J'ai essayé SwingWorker, appelable & Runnable pour effectuer le traitement, mais peu importe ce que je fais, lors du traitement de la liste (ce qui peut prendre jusqu'à quelques minutes, car il est lié IO), l'interface graphique est bloqué.

Je sens qu'il est probablement la façon dont j'appelle les fils ou quelque chose, ou pourrait-il faire avec la fonction graphique? Ce n'est pas enfilée car il est très rapide.

Je dois faire les deux étapes de traitement pour trop, alors quelle est la meilleure façon d'assurer le second a attendu le premier? Je l'ai utilisé join (), puis sur

while(x.isAlive())  
{  
        Thread.sleep(1000);  
}

pour essayer d'assurer, mais je suis inquiet que cela pourrait être la cause de mon problème aussi.

Je l'ai cherchée partout quelques conseils, mais que je ne trouve pas que je suis sûr que je fais quelque chose de stupide ici.

Était-ce utile?

La solution

Le problème est, votre longue tâche en cours d'exécution bloque le fil qui maintient l'interface réactive.

Qu'est-ce que vous devez faire est de mettre la longue tâche en cours d'exécution sur un autre thread.

Voici quelques façons communes de le faire utilisent minuteries ou SwingWorker .

Le tutoriels Java ont beaucoup d'informations au sujet de ces choses leur leçon de concurrence.

Pour vous assurer que la première tâche se termine avant la seconde, il suffit de les mettre à la fois sur le même fil. De cette façon, vous ne serez pas à vous soucier de garder deux threads différents chronométrés correctement.

Voici une exemple d'implémentation d'un SwingWorkerFor votre cas:

public class YourTaskSwingWorkerSwingWorker extends SwingWorker<List<Object>, Void> {
    private List<Object> list
    public YourClassSwingWorker(List<Object> theOriginalList){
        list = theOriginalList;
    }

    @Override
    public List<Object> doInBackground() {
        // Do the first opperation on the list
        // Do the second opperation on the list

        return list;
    }

    @Override
    public void done() {
        // Update the GUI with the updated list.
    }
}

Pour utiliser ce code, lorsque l'événement pour modifier la liste est tiré, créez un nouveau SwingWorker et lui dire de commencer.

Autres conseils

Vous ne retournez pas le fil swing correctement. Je me rends compte que vous utilisez appelable / runnable mais je devine que vous ne le faites pas droit (même si vous ne le code ne suffit pas de poster pour en être sûr).

La structure de base serait:

swingMethod() { // Okay, this is a button callback, we now own the swing thread
    Thread t=new Thread(new ActuallyDoStuff());
    t.start();
}

public class ActuallyDoStuff() implements Runnable {
    public void run() {
        // this is where you actually do the work
    }
}

Ceci est juste à côté du haut de ma tête, mais je devine que vous ne faites pas non plus la Thread.Start et appelez directement à la place la méthode d'exécution, ou vous faites autre chose dans la première méthode que les verrous vers le haut (comme Thread.join). Aucune de ces libérerait le fil de swing. La première méthode DOIT revenir rapidement, la méthode run () peut prendre aussi longtemps qu'il veut.

Si vous faites un Thread.join dans la première méthode, le fil n'est pas retourné au système!

Edit: (deuxième édition en fait) Je pense parler au problème que vous vous sentez réellement - vous voudrez peut-être penser davantage en termes d'un modèle / vue / contrôleur. Le code que vous écrivez est le contrôleur (la vue est généralement considéré comme les composants sur l'écran - vue / contrôleur sont généralement très étroitement liés)

.

Lorsque votre contrôleur reçoit l'événement, il devrait passer le travail hors de votre modèle. La vue est alors hors de l'image. Il n'attend pas le modèle, il vient de faire.

Une fois le modèle terminé, il doit alors dire au contrôleur pour faire autre chose. Elle le fait par l'une des méthodes d'Invoke. Ce transfère le contrôle au contrôleur et vous allez sur votre chemin joyeux. Si vous pensez de cette façon, séparer le contrôle et délibérément passer avant et en arrière ne se sent pas si encombrant, et il est en fait très commun de le faire de cette façon.

Il semble que le problème pourrait être que vous attendez sur les fils pour terminer à l'intérieur du fil de l'interface graphique. Votre fil GUI ne doit pas attendre sur ces sujets, à la place, vous devriez avoir les threads de travail invoquent une méthode sur le fil de l'interface graphique qui définit un drapeau. Lorsque les deux drapeaux sont fixés alors vous savez les deux fils finis et que vous pouvez faire le graphique.

Je ne peux pas vraiment parler au modèle de thread swing, mais:

  

Je dois faire les deux étapes de traitement pour trop, alors quelle est la meilleure façon d'assurer le second a attendu le premier?

Pour ce type de fonctionnalité, je vous suggère de créer deux threads de travail, et embed un courtier JMS. Fournir un travail aux deux fils par des messages passant dans les files d'attente JMS qu'ils lisent à partir. Votre fil GUI est libre d'examiner les files d'attente pour déterminer quand le travail se passe et représentent l'état d'avancement dans votre interface utilisateur.

La solution à mon problème était un mélange de jjnguy et les réponses de Bill K, donc merci beaucoup pour que les gars. Je avais besoin d'utiliser des fils dans un SwingWorker comme ceci:

public class Worker extends SwingWorker<Void, Void>   
{  
    private List<Object> list;  
    public YourClassSwingWorker(List<Object> theOriginalList){  
        list = theOriginalList;  
    }

    @Override
    public List<Object> doInBackground() {
        Thread t = new Thread(new ProcessorThread(list));  
        t.start();
    }

    @Override
    public void done() {
        // draw graph on GUI
    }
}  
class ProcessorThread implements Runnable {  
    //do lots of IO stuff  
    Thread t2 = new Thread(new SecondProcess());
    t2.start();  
}

fait que tout le travail était fait par des fils de travailleurs loin de l'interface graphique, et assurant que la SwingWorker lui-même ne faisait pas tout le travail, ce qui aurait pu être un problème.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top