2010-09-22 6 views
1

Je travaille sur un projet Java avec mon équipe au travail. Pour résumer, nous avons une classe principale qui a une méthode qui instancie et appelle une classe "Save". Cette classe "Save" enregistre les fichiers sur un serveur avec un couple de constructeurs et une poignée de méthodes visibles et non visibles. La classe est gourmande en temps CPU et empêche l'application principale d'afficher une fenêtre de dialogue de barre de progression indiquant à l'utilisateur le statut de la sauvegarde. Ils m'ont demandé de modifier la classe "Save" afin qu'elle apparaisse sur son propre thread afin que le reste de l'application principale puisse faire les petites tâches d'affichage des informations à l'utilisateur.Aide à l'implémentation de Runnable en Java

Voici un concept général de celui-ci:

class MainApp{ 
    ... 

    private void doSave() 
    { 
     Save s = new Save(); 
     StatusWindow sw = new StatusWindow(); 

     if save_this 
      s.saveThis(sw); 
     if save_that 
      s.saveThat(sw); 

     ... 
    } 
    ... 
} 

class Save{ 
    ... 

    public void saveThis(StatusWindow s) 
    { 
     //alot of code 
     s.update; 

    } 
    public void saveThat(StatusWindow s) 
    { 
     //alot of code 
     s.update; 
    } 
    ... // some non-visible methods, even more code 
} 

Je suis novice suis actuellement avec des fils en Java, mais j'ai une compréhension de base de la façon dont ils travaillent. D'après ce que je comprends, une classe qui implémente Runnable, quand elle est instanciée comme un nouveau thread, la méthode run() est exécutée. Le problème est, puisqu'il existe différentes méthodes pour différents types d'enregistrement pour différents types de fichiers, comment puis-je implémenter ces méthodes dans la méthode run()? La méthode run() est-elle la seule méthode qui est exécutée lorsque la classe est instanciée dans un nouveau thread et que .start() est appelée?

Quelle serait une bonne solution à ce problème? La classe "Save" aurait-elle besoin d'être repensée pour l'implémenter avec Runnable?

Si plus de détails sont nécessaires, s'il vous plaît faites le moi savoir. Merci pour tout aperçu!

Mise à jour: Merci à tous pour votre aide! Ces solutions seront utiles pour l'avenir.

Répondre

7

Le moyen le plus simple est de faire un runnable pour chacun. Au lieu de passer des paramètres dans run, faites-en des champs d'instance.

class SaveThatCommand implements Runnable { 
    private final StatusWindow s; 
    //constructor that initializes s 
    public void run() { 
     //save that code 
     s.update(); 
    } 
} 

Un moyen plus facile d'y arriver, en fonction de vos besoins, est de faire une classe interne anonyme

public void doSave(final StatusWindow s) { 
    if (saveThis) { 
     Thread t = new Thread(new Runnable() { 
      public void run() { 
       saveThis(s); 
      } 
     }); 
     t.start(); 
    } 
    //... 
} 

Et vous êtes un peu incorrect: la méthode d'exécution est exécutée quand il est passé dans le constructeur d'un thread , puis start() est appelé sur ce thread.

+0

Oui je suis totalement oublié d'ajouter .start() là-dedans, je vais modifier ma question. Thanx :) –

+0

J'aime la deuxième suggestion, il semble rapide et facile à mettre en œuvre pour l'instant –

0

Il y a deux façons de le faire:

a) Vous pouvez déplacer le code avec le cas du bloc dans la méthode run().

b) Vous pouvez avoir une classe par type de document qui implémente runnable.

L'approche a) est plus simple car elle nécessite moins de changements au code existant. Mais l'approche b) est la manière orientée objet de le faire: "Une classe par tâche".

2

Une solution complète consisterait à étendre la classe Runnable et à transmettre les paramètres requis et le type de sauvegarde nécessaire au constructeur.Ensuite, vous pouvez les exécuter avec:

new Thread(saveRunnable).start();

Une solution plus simple serait de mettre en œuvre un modèle comme celui-ci à l'intérieur de la classe sauver:

 
public void saveThis(StatusWindow s) { 
    Runnable r = new Runnable() { 
    private StatusWindow s; 
    public Runnable setStatusWindow(StatusWindow s) { 
     this.s = s; 
     return this; 
    } 

    @Override 
    public void run() { 
     this.Save.saveThisInternal(this.s); 
    } 
    }.setStatusWindow(s); 
    new Thread(r).start(); 
} 

public void saveThisInternal(StatusWindow s) { 
    //alot of code 
    s.update(); 
} 
3

Vos collègues appellent probablement économiser de plus d'un endroit dans la principale application et voudrait éviter d'avoir à changer tout le code pour supporter l'enregistrement en parallèle. De même, en général, la plupart des gens ne préfèrent pas créer leurs propres threads et préfèrent utiliser ExecutorService. Voici donc comment le faire avec seulement modifier la classe Save et en utilisant un exécuteur:

class Save{ 
    private static final ExecutorService executor = Executors.newCachedThreadPoolExecutor(); 
    //or fixed, or whatever you want. Maybe single thread executor is best if the Save code is not well suited to concurrency. 

    static { 
     Runtime.getRuntime().addShutdownHook(
      new Thread() { 
       public void run() { 
        executor.shutdown(); 
       } 
      } 
     ); 
    } 

    public void saveThis(StatusWindow s) 
    { 
     executor.execute(new SaveThis(s)); 
    } 
    public void saveThat(StatusWindow s) 
    { 
     executor.execute(new SaveThat(s)); 
    } 
    ... // some non-visible methods, even more code 

    private class SaveThis implements Runnable { 
     //StatusWindow member variable and constructor 
     public void run() { 
      //alot of code 
      s.update; 
     } 
    } 

    private class SaveThat implements Runnable { 
     //StatusWindow member variable and constructor 
     public void run() { 
      //alot of code 
      s.update; 
     } 
    } 
} 
+0

+1 Merci Tim! Je garderai cet esprit pour l'avenir –