web-dev-qa-db-fra.com

Meilleure pratique pour la gestion des exceptions dans les threads Java

lecteur de longue date, premier demandeur ici. J'ai un service qui écrit des données dans une base de données par lots. Il contient un tampon qui est surveillé par un thread séparé. Chaque fois que le tampon atteint une certaine taille ou qu'une certaine période de temps s'est écoulée depuis la dernière écriture, le thread écrit les données dans la base de données.

En Java, chaque fois qu'il y a une exception dans le thread du moniteur, il meurt silencieusement et ne fait plus rien.

Existe-t-il une meilleure pratique établie de gestion des exceptions dans de tels threads? Le thread doit être en cours d'exécution à tout moment et doit imprimer une exception dans le journal, le cas échéant.

Il existe des solutions potentielles à cela:

  1. Enveloppez toutes les méthodes dans des blocs try/catch, interceptez toutes les exceptions et demandez à un enregistreur d'imprimer les messages. (Beaucoup trop moche à mon goût)
  2. Enregistrez un gestionnaire d'exceptions non capturé et traitez-y les exceptions. (peut être?)
  3. N'utilisez pas un thread, mais un appelable ou un exécutable à la place. (Je ne sais pas si cela convient aux threads toujours actifs)
  4. Rien d'autre?
7
JohnEye

Tout d'abord, je ne comprenais pas pourquoi vous avez besoin du thread de moniteur et quel est son objectif. La seule raison pour laquelle je pourrais penser est si le thread de moniteur est un thread en cours d'exécution qui surveille simplement le tampon et appelle périodiquement l'écriture de la base de données. Si tel est le but, je préfère le faire avec des planificateurs, par exemple planifier une écriture toutes les n secondes et écrire tout le tampon dans la base de données. Ensuite, il vous suffit d'estimer le nombre de secondes dont vous avez besoin pour que le taux de programmation ne déborde pas.

Quant à la gestion des exceptions dans les threads, je voudrais d'abord réessayer l'écriture. En fin de compte, si tout échoue, la première chose à faire est de récupérer les données afin qu'elles ne se perdent pas.

La manière dont les exceptions sont censées être gérées consiste à identifier les exceptions qui peuvent se produire, puis à ne gérer que ces exceptions spécifiques. Vous ne devriez jamais faire des choses comme catch (Exception e). Étant donné que le service d'écriture de base de données est un service général, je voudrais qu'il propage l'exception à l'appelant, puis que l'appelant gère l'exception, car le service ne peut pas savoir quel comportement l'appelant souhaite.

La façon dont vous devez gérer ces exceptions spécifiques dépend de vous et presque personne ne peut vous aider. Si vous ne pouvez pas gérer les exceptions dans le bloc finally et qu'elles nécessitent l'attention du développeur, je les consignerais ou informerais le développeur via un autre canal de communication, par exemple e-mail, Slack.

6
leonz

Vous n'avez jamais mentionné si les exceptions levées DOIVENT être gérées/enregistrées par le thread principal ou non. Je suppose que "cela n'a pas d'importance, j'ai juste besoin de journaliser l'exception et d'éviter la corruption des threads".

Si mon hypothèse est correcte, alors vous pourriez simplement avoir besoin de mettre le try/catch sur la méthode run de Runnable, mais cette méthode doit être exécutée sur une boucle infinie et dormir de temps en temps:

final Thread t = new Thread(new Runnable(){
    @Override
    public void run(){
          long lastTimeFlushed = getCurrentTime();
          while(true){
                try{
                     if(bufferLimitExceeded() || timeoutExceeded(lastTimeFlushed)){
                           flushToDB();
                           lastTimeFlushed = getCurrentTime();
                     } 
                     Thread.sleep(500);
                }catch(final InterruptedException ex){
                     // you'll need to decide whether to ignore or not thread's interruption
                     // This example is in case you decide not to ignore it
                     Thread.currentThread().interrupt();
                }catch(final Exception ex){
                     logError(ex);
                } 
          } 
     } 
});

t.start();

De cette façon, votre thread ne mourra pas et vous n'auriez qu'à ajouter try/catch en un seul endroit.

Avertissement: j'ai écrit cela en utilisant mon téléphone. Désolé s'il y a des fautes de frappe (surtout dans le code)

4
DanielCuadra