2010-08-05 5 views
2

Je sais que c'est mal conseillé mais j'essaie toujours de trouver une méthode pour interrompre un thread qui se bloque, à partir d'un autre thread qui garde le temps. Ce que je fais est: Je démarre le fil du moniteur juste avant qu'une opération de réseau douteuse ne soit sur le point de se produire. Ce thread est censé surveiller le temps écoulé depuis son démarrage et si le temps dépasse une valeur seuil, il tue le thread qui l'a initialement démarré. Afin d'informer ce nouveau thread, quel thread doit être tué, l'objet du nouveau thread, est passé un objet du Thread à surveiller.Comment interrompre un autre thread à partir d'un moniteur Thread

En bref, voici ce qui se passe:

A crée B, B crée C, B dit C sur lui-même, C garde le temps, si le temps expire C tue B (je passe après les détails à C Méthode d'exécution de B en utilisant "currentThread()" et j'ai confirmé que l'objet correct est en effet passé)

Maintenant, le problème est que, cela, ne fonctionne pas, pour une raison quelconque, l'appel à B.interrupt () tue C lui-même.

[Note: Les lettres majuscules désignent les noms de fil]

+0

Quelle est la raison pour C mourir? Toute trace de pile? Savez-vous à coup sûr qu'il meurt? Pouvez-vous poster le code de votre thread de surveillance? –

+0

http://pastebin.com/JVfpkqEg Voici un lien vers le code pour le moniteur, "Hourglass" est juste une petite classe de temporisation que j'ai faite, dans le constructeur, vous passez un délai d'attente en secondes, puis vous pouvez démarrer, arrêter ou vérifier les tâches pour l'achèvement. – angryInsomniac

+0

commentaire suite: Je ne vois aucune raison pour que C meure, il n'y a pas d'erreur signalée donc je ne peux pas vous donner de pile. Je suis sûr qu'il meurt pendant que je regarde l'exécution de thread en temps réel avec eclipse, dès que les instructions requises sont exécutées, thread C matrices. – angryInsomniac

Répondre

-1

Ceci est en fait un comportement normal si vous me demandez. Si vous interrompez B, il sera collecté. Puisque la seule référence à C est alors aussi GC'd, elle cessera d'exister/fonctionnera.

La meilleure idée peut être de s'assurer qu'il y a un thread qui gère les threads B et C (et injecte le thread C dans le thread B). Ainsi, il y a toujours une référence au thread C et il peut tuer le thread B. (mais attention à ce que vous faites avec le thread B dans le thread de gestion)

+0

En fait, c'est ce que je croyais, cependant, ce que j'observe, c'est que C est détruit et B continue d'exister. – angryInsomniac

+0

Je pense que les threads ont des références d'objets ThreadGroup. Je ne thread pas C est CG'd dans cet exemple –

+0

Oui, les threads ne sont pas GCd comme ça. –

1

Vérifiez si vous obtenez SecurityException lorsque vous appelez B.interrupt() . En outre, êtes-vous sûr que votre B.interrupt() ne retourne pas simplement et termine le C finit avec succès? Sur la base de javadocs, il semble que l'appel du thread C de B.interrupt() définit l'état d'interruption du thread B et se termine. Je ne pense pas que le thread B aura une exception dans votre cas, à moins qu'il ne réponde à des exigences spéciales (comme, attendre sur le moniteur, attendre InterruptibleChannel, etc).

+0

Pour autant que je peux voir, aucune exception de quelque sorte n'est lancée nulle part dans le code – angryInsomniac

+0

Pouvez-vous s'il vous plaît poster le code de votre fil de surveillance? –

2

Je pense que quelque chose ne va pas avec votre code (sauf si je n'ai pas obtenu votre droit de spécification). Le code ci-dessous exécute comme prévu (désolé pour la structure imbriquée horribles):

sortie était:

C is about to interrupt B 
B is interrupted 
C is still alive... is B alive yet?false 
code

était:

import java.util.concurrent.CountDownLatch; 
import java.util.concurrent.atomic.AtomicReference; 


public class Scrap { 
    public static void main(String[] args) { 
     Thread A = new Thread() { 
      @Override 
      public void run() { 
       Thread B = new Thread() { 
        @Override 
        public void run() { 
         final CountDownLatch latch = new CountDownLatch(1); 
         final AtomicReference<Thread> pointer = new AtomicReference<Thread>(); 
         Thread C = new Thread() { 
          @Override 
          public void run() { 
           try { 
            //wait for B to be ready 
            latch.await(); 
            Thread.sleep(2000); 
            System.out.println("C is about to interrupt B"); 
            pointer.get().interrupt(); 
            Thread.sleep(2000); 
            System.out.println("C is still alive... is B alive yet? " + pointer.get().isAlive()); 

           } catch (InterruptedException e) { 
            System.out.println("C interrupted"); 
            return; 
           } 
          } 
         };//C 
         C.start(); 
         latch.countDown(); 
         //Not sure how you did it, so just going with this: 
         pointer.set(Thread.currentThread()); 


         try { 
          Thread.sleep(5000); 
         } catch (InterruptedException e) { 
          System.out.println("B is interrupted"); 
          return; 
         } 
         System.out.println("B survived"); 

        } 
       };//B 
       B.start(); 
      } 
     }; 
     A.start(); 
    } 
} 

Mon (sauvage) estimation serait la visibilité inter-thread . Dans le code ci-dessus, j'utilise une référence atomique pour assurer la visibilité. Dans le cas où vous ne l'avez pas fait, il est possible que quel que soit le champ que vous avez passé la référence de Thread B (la valeur de s) puisse être invisible pour C. Alors, quand C tente d'interrompre cet objet Thread, il voit null et l'interruption aboutit à NullPointerExceptin , et d'une certaine façon vous ne le remarquez pas?

1

Une autre possibilité est que C interrompt avec succès et renvoie, mais B ne répond pas à cela. Ceci est tout à fait possible parce que l'interruption n'a d'effet que si B est codé en conséquence.

Il y a 2 façons de réagir à l'interruption.
1.Vérifiez indicateur d'interruption (généralement avant les opérations qui prennent longtemps)

if(Thread.currentThread().isInterrupted()){ 
    log.info("Cancel requested"); 
    return; 
} 
someStuffThatTakesLongTimeToExecute(); 

2.Act sur exception d'interruption

catch(InterruptedException e){ 
    log.info("Cancel Requested"); 

    //Preserve interrupted status. 
    //If this class is the owner of the thread, 
    //Not necessary. 
    Thread.currentThread().interrupt(); 

    return; 
} 
Questions connexes