J'ai un fil qui télécharge des données et je veux attendre que le téléchargement soit terminé avant de charger les données. Y a-t-il un moyen standard de faire cela?
Plus d'informations:
J'ai une classe de téléchargement qui obtient des données à partir d'une URL (POJOs sérialisés). Le téléchargement est exécutable et observable. Il garde une trace des octets téléchargés et de la taille du téléchargement. J'ai une barre de progression qui affiche la progression à l'utilisateur. L’interface graphique observe Download pour mettre à jour la barre de progression.
Une fois le POJO téléchargé, je souhaite l’obtenir et passer à l’étape suivante. Chaque étape doit attendre que la précédente se termine. Le problème est que je ne peux pas penser à un moyen de suspendre mon application pour attendre le fil de téléchargement. Une fois le téléchargement terminé, je souhaite appeler download.getObject (), qui renvoie les données sous forme d'objet. Je peux ensuite le lancer et passer au téléchargement suivant.
J'ai une classe d'assistance qui gère les URL à télécharger et effectue tous les appels à Télécharger. Cet appel appellera getObject et fera le casting. Le GUI appelle helper.getUser (). helper démarre le thread en cours d'exécution et je veux qu'il sache quand il est terminé afin qu'il puisse renvoyer l'objet projeté.
Des suggestions/exemples? Je suis au début de cette conception, donc je suis disposé à la changer.
Merci de bien vouloir.
Mise à jour:
J'ai suivi http://download.Oracle.com/javase/6/docs/api/javax/swing/SwingWorker.html#get et utilisé modal pour bloquer jusqu'à la fin du fil. Le code était très compliqué et je n'aime pas cette approche. Je continuerai à essayer de trouver un moyen "propre" de gérer le flux de travail des processus de téléchargement.
Thread
a une méthode qui le fait pour vous join qui bloquera jusqu'à ce que le thread ait fini de s'exécuter.
Vous pouvez utiliser un CountDownLatch
du paquet Java.util.concurrent
. C'est très utile lorsque vous attendez qu'un ou plusieurs threads soient terminés avant de poursuivre l'exécution dans le thread en attente.
Par exemple, attendre que trois tâches soient terminées:
CountDownLatch latch = new CountDownLatch(3);
...
latch.await(); // Wait for countdown
Les autres threads appellent alors chacun latch.countDown()
lorsque leurs tâches sont terminées. Une fois le compte à rebours terminé, trois dans cet exemple, l'exécution se poursuivra.
SwingWorker a doInBackground()
que vous pouvez utiliser pour effectuer une tâche. Vous avez la possibilité d'appeler get()
et d'attendre la fin du téléchargement. Vous pouvez également remplacer la méthode done()
qui sera invoquée sur le thread d'envoi d'événements une fois que SwingWorker aura terminé.
Swingworker présente des avantages par rapport à votre approche actuelle en ce sens qu’il possède de nombreuses fonctionnalités que vous recherchez, il n’est donc pas nécessaire de réinventer la roue. Vous pouvez utiliser les méthodes getProgress()
et setProgress()
comme alternative à un observateur sur le runnable pour la progression du téléchargement. La méthode done()
, comme je l'ai indiqué ci-dessus, est appelée une fois que l'opérateur a terminé son exécution et est exécutée sur l'EDT. Cela vous permet de charger les données une fois le téléchargement terminé.
De meilleures alternatives à la méthode join () ont évolué au fil du temps.
ExecutorService.html # invokeAll est une alternative.
Exécute les tâches données, en renvoyant une liste des contrats à terme contenant leur statut et leurs résultats lorsque tous sont terminés. Future.isDone () est vrai pour chaque élément de la liste renvoyée.
Notez qu'une tâche terminée peut s'être terminée normalement ou en lançant une exception. Les résultats de cette méthode ne sont pas définis si la collection donnée est modifiée pendant que cette opération est en cours.
ForkJoinPool ou Executors.html # newWorkStealingPool fournit d'autres alternatives pour atteindre le même objectif.
Exemple d'extrait de code:
import Java.util.concurrent.*;
import Java.util.*;
public class InvokeAllDemo{
public InvokeAllDemo(){
System.out.println("creating service");
ExecutorService service = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
List<MyCallable> futureList = new ArrayList<MyCallable>();
for ( int i=0; i<10; i++){
MyCallable myCallable = new MyCallable((long)i);
futureList.add(myCallable);
}
System.out.println("Start");
try{
List<Future<Long>> futures = service.invokeAll(futureList);
}catch(Exception err){
err.printStackTrace();
}
System.out.println("Completed");
service.shutdown();
}
public static void main(String args[]){
InvokeAllDemo demo = new InvokeAllDemo();
}
class MyCallable implements Callable<Long>{
Long id = 0L;
public MyCallable(Long val){
this.id = val;
}
public Long call(){
// Add your business logic
return id;
}
}
}
Vous pouvez utiliser join()
pour attendre que tous les threads soient terminés. Conservez tous les objets des threads dans la liste globale ArrayList au moment de la création des threads. Après cela, gardez-le en boucle comme ci-dessous:
for (int i = 0; i < 10; i++)
{
Thread T1 = new Thread(new ThreadTest(i));
T1.start();
arrThreads.add(T1);
}
for (int i = 0; i < arrThreads.size(); i++)
{
arrThreads.get(i).join();
}
Vérifiez ici pour plus de détails: http://www.letmeknows.com/2017/04/24/wait-for-threads-to-finish-Java
J'imagine que vous appelez votre téléchargement dans un fil de fond tel que celui fourni par SwingWorker. Si tel est le cas, appelez simplement votre code suivant de manière séquentielle dans la même méthode doInBackground de SwingWorker.
En règle générale, lorsque vous souhaitez attendre la fin d'un thread, vous devez appeler join () dessus.
Des suggestions/exemples? J'ai suivi
SwingWorker
... Le code était très compliqué et je n'aime pas cette approche.
Au lieu de get()
, qui attend son achèvement, utilisez process()
et setProgress()
pour afficher des résultats intermédiaires, comme suggéré dans ce simple exemple ou cette relation exemple .
La méthode join () permet à un thread d'attendre l'achèvement d'un autre processus. Cependant, comme pour la veille, la jointure dépend du système d'exploitation, vous ne devez donc pas présumer que celle-ci attendra exactement aussi longtemps. comme vous le spécifiez.