IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Java Discussion :

Thread et garbage collector.


Sujet :

Java

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2005
    Messages
    37
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2005
    Messages : 37
    Par défaut Thread et garbage collector.
    Bonjour à tous.

    J'ai une classe qui lance un thread dans le constructeur, thread qui peut servir n'importe quand (et qui ne doit pas s'arrêter). L'objet qui a lancé le thread n'est donc jamais détruit et le thread ne s'arrête jamais.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class Toto {
    Toto() {
    new Thread() {
    run() { while(true);}
    }.start();
    }
     
    public static void main() {
    Toto t = new Toto();
    t = null;
    }
    }
    J'aimerais que le thread s'arrête quand on n'utilise plus l'objet. Une solution est d'ajouter une méthode stopThread() mais est-ce qu'il y a un moyen de savoir que l'objet n'a plus de référence vers lui, pour arrêter le thread automatiquement ?
    Je ne sais pas si j'ai été clair.
    Merci pour vos réponses

  2. #2
    Membre chevronné Avatar de binouzzz19
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    385
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Avril 2007
    Messages : 385
    Par défaut
    Bonjour,

    Je pense qu'il faudrait que tu regardes du côté de la méthode finalize(). Tu la redéfinit. Regarde de ce coté pour la libération du thread : http://java.developpez.com/faq/java/...HREAD_terminer

    Cdlt.

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2005
    Messages
    37
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2005
    Messages : 37
    Par défaut
    Citation Envoyé par binouzzz19 Voir le message
    Bonjour,

    Je pense qu'il faudrait que tu regardes du côté de la méthode finalize(). Tu la redéfinit. Regarde de ce coté pour la libération du thread : http://java.developpez.com/faq/java/...HREAD_terminer

    Cdlt.
    Salut.
    merci pour ta réponse mais tu ne m'as pas bien compris :
    La méthode finalize() de Toto n'est jamais appelée puisque le Thread est lancé et qu'il a une référence vers l'objet t qu'il faudrait détruire.
    Donc il faudrait que le thread sache qu'il n'existe aucune autre référence sur t que la sienne.
    Ou un autre moyen qui arrive au même résultat (thread arrêté) me conviendrait aussi.

  4. #4
    Membre chevronné Avatar de binouzzz19
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    385
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Avril 2007
    Messages : 385
    Par défaut
    Salut,

    Quand je te parlais de finalize(), c'était pour l'objet t (instance de Toto). Si ton objet t n'est pas "détruit" manuellement, il va continuer à tourner tout le temps, du coup, ton thread aussi. Si tu veux arrêter ton thread lorsque 't' n'existe plus c'est que tu a fermé 't' manuellement. De ce fait, tu peux redéfinir cette méthode pour ton besoin.

    Cordialement.

  5. #5
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2005
    Messages
    37
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2005
    Messages : 37
    Par défaut
    Citation Envoyé par binouzzz19 Voir le message
    Si ton objet t n'est pas "détruit" manuellement, il va continuer à tourner tout le temps, du coup, ton thread aussi. Si tu veux arrêter ton thread lorsque 't' n'existe plus c'est que tu a fermé 't' manuellement.
    ok, mais on ne peut pas détruire d'objet manuellement.
    Donc je dois arrêter le thread manuellement. Or je voudrais savoir comment arrêter le thread automatiquement (en détectant qu'il n'y a plus de référence vers t).
    Merci

  6. #6
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    Salut,


    Je ne comprend pas l'intérêt de ton thread ? Que veux-tu faire avec précisément ?

    a++

  7. #7
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2005
    Messages
    37
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2005
    Messages : 37
    Par défaut
    Salut.
    J'utilise JNI pour exécuter des commandes DDE.
    DDE est mono-thread, donc j'utilise un seul thread créé lors de la connexion pour exécuter mes commandes DDE. Ça marche bien (sauf que je dois arrêter le thread manuellement).
    Utiliser un thread en Java m'éviterait de le faire dans l'appli native (C++), mais si ce n'est pas possible j'utiliserai des threads dans l'appli native. Ou alors je resterai en mono-thread.
    Mais j'aimerais quand même savoir s'il y a un moyen de détruire un objet ayant lancé un thread avec le GC (on sait jamais ça pourrait servir).
    Merci.

  8. #8
    Membre chevronné Avatar de binouzzz19
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    385
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Avril 2007
    Messages : 385
    Par défaut
    Comment veux-tu qu'il n'y ait pas de référence à t ?

    Désolé je n'arrive pas à comprendre. C'est peut-être au dessus de mes compétences ?!

    http://philippe.prados.name/Langage/...e/finalize.pdf

    Cdlt.

  9. #9
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2005
    Messages
    37
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2005
    Messages : 37
    Par défaut
    Citation Envoyé par binouzzz19 Voir le message
    Comment veux-tu qu'il n'y ait pas de référence à t ?
    par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Toto t = new Toto();
    t = null; // il n'y a plus de référence de t hormis celle du thread
    Le garbage collector ne supprime pas t (à juste titre), mais dans mon cas le thread ne sert plus à rien et je voudrais qu'il se termine lui-même en sachant que t n'est plus utilisé.

    Désolé je n'arrive pas à comprendre. C'est peut-être au dessus de mes compétences ?!

    http://philippe.prados.name/Langage/...e/finalize.pdf

    Cdlt.
    merci quand même
    et puis il n'y a peut-être pas de solution à mon problème (à part celles que j'ai mentionnées).

  10. #10
    Membre chevronné Avatar de binouzzz19
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    385
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Avril 2007
    Messages : 385
    Par défaut
    Extrait du lien :

    Pour que la méthode TempFile.finalize() soit appelée, il faut qu'il n'existe plus de pointeur sur l'instance et que le ramasse-miettes entre en action.
    TempFile tmp=new TempFile(); tmp=null; // Va détruire le fichier
    Le ramasse-miettes intervient en tâche de fond. Il n'est pas possible de prédire quand la méthode finalize() sera appelée. Cela veut dire que la ressource file.tmp ne sera pas disponible tant que le ramasse-miettes n'est pas intervenu. Pour demander explicitement le nettoyage de la mémoire, il faut appeler la méthode System.gc(). Cette méthode lance en tâche de fond le ramasse-miettes. La méthode System. runFinalization() lance le ramasse-miettes et attend que toutes les méthodes finalize() soient effectuées avant de rendre la main.
    Lorsqu'un programme se termine, les méthodes finalize() ne sont pas forcément appelées. Pour garantir l'appel aux méthodes finalize() avant la fin du programme, il faut appeler System.runFinalizationOnExit()avec la valeur true. Ce paramétrage permet d'imposer l'appel de toutes les méthodes finalize() de toutes les instances, avant de sortir du programme. Cela permet de garantir que le fichier temporaire précédent sera détruit.

  11. #11
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    bobo21 > Tu pourrais donner un exemple concret de code ?

    Pourquoi ne pas simplement utiliser un bloc synchronized ?

    a++

  12. #12
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2005
    Messages
    37
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2005
    Messages : 37
    Par défaut
    Citation Envoyé par adiGuba Voir le message
    bobo21 > Tu pourrais donner un exemple concret de code ?

    Pourquoi ne pas simplement utiliser un bloc synchronized ?
    Voilà mon code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    public class DDE {
     
    	DDE() {
    		new Thread() {
    			run() {
    				synchronized(DDE.this) {
    					while(true) {
    						DDE.this.wait();
     
    						// notification reçue
    						// exécution
     
    						DDE.this.notifyAll();
    					}
    				}
    			}
    		}
    	}
     
    	String action;
     
    	public synchronized void executeAction(String action) {
    		this.action = action;
    		notifyAll();
    		this.wait();
     
    		// action exécutée
    	}
    }
    mais le code suivant est suffisant pour comprendre le problème (interdépendance entre le thread et l'objet).
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public class Toto {
    	Toto() {
    		new Thread() {
    			run() {
    				while(true);
    			}
    		}.start();
    	}
     
    public static void main() {
    	Toto t = new Toto();
    		t = null;
    	}
    }
    De toute façon je posais la question juste au cas où. Je ne pense pas qu'il existe de solution (ça serait compliqué pour pas grand chose au final).
    Merci à vous 2.
    A+

  13. #13
    Membre expérimenté Avatar de hydraland
    Profil pro
    Développeur Java
    Inscrit en
    Mai 2006
    Messages
    179
    Détails du profil
    Informations personnelles :
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Java

    Informations forums :
    Inscription : Mai 2006
    Messages : 179
    Par défaut
    Salut,

    Regarde du coté des WeakReference. L'idée c'est que ton thread aurai une WeakReference sur ton objet et non une référence normale.

    A+
    Hydraland

  14. #14
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    Ok je comprend mieux ton besoin

    Il te faut 2 choses :
    • Vérifier dans ton thread le status "interrupted" du thread. Cela te permettra d'arrêter le thread.
    • Conserver la référence vers ton thread dans un attribut d'instance, afin de pouvoir l'interrompre.

    Ce qui donne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    public class DDE {
     
    	private final Thread thread;
     
    	public DDE() {
    		this.thread = new Thread() {
    			public void run() {
    				synchronized(DDE.this) {
    					try {
    						while(!Thread.interrupted()) {
    							DDE.this.wait();
     
    							// notification reçue
    							// exécution
     
    							DDE.this.notifyAll();
    						}
    					} catch (InterruptedException e) {
    						// Interruption recu
    						// (on sort du while)
    					}
    				}
    			}
    		};
    		this.thread.start();
    	}
    Maintenant il ne te reste plus qu'à implémenter une méthode qui provoquera l'interruption sur ton thread :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    	public void close() {
    		if (this.thread.isAlive()) {
    			this.thread.interrupt();
    		}
    	}
    Lorsque ton thread reçoit l'interruption, il y a 2 cas de figure :
    • Soit tu es en attente dans le wait(), et cela génèrera une exception qui te fera sortir de la boucle (et donc le thread s'arrêtera).
    • Soit tu effectues des traitements qui vont ignorer l'interruption, et dans ce cas tu sortira de la boucle au prochain passage car la condition sera fausse.


    L'appel à la méthode close() devra être fait manuellement. Toutefois tu peux mettre en place un garde-fou via finalize() :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    	@Override
    	protected void finalize() throws Throwable {
    		try {
    			close();
    		} finally {
    			super.finalize();
    		}
    	}

    a++

    PS : Et si tu utilises Java 5 ou plus, tu pourrais te tourner vers les BlockingQueue pour "passer" les actions à ton thread : c'est plus simple que les wait/notify

  15. #15
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2005
    Messages
    37
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2005
    Messages : 37
    Par défaut
    Citation Envoyé par hydraland Voir le message
    Salut,

    Regarde du coté des WeakReference. L'idée c'est que ton thread aurai une WeakReference sur ton objet et non une référence normale.

    A+
    Hydraland
    Salut.
    Merci beaucoup ça correspond exactement à ce que je cherche.
    Je vais essayer ça

    edit : en fait je ne peux pas l'utiliser parce que tant que le thread est lancé il ne veut pas supprimer l'objet.

  16. #16
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2005
    Messages
    37
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2005
    Messages : 37
    Par défaut
    Citation Envoyé par adiGuba Voir le message
    Ok je comprend mieux ton besoin

    Lorsque ton thread reçoit l'interruption, il y a 2 cas de figure :

    * Soit tu es en attente dans le wait(), et cela génèrera une exception qui te fera sortir de la boucle (et donc le thread s'arrêtera).
    * Soit tu effectues des traitements qui vont ignorer l'interruption, et dans ce cas tu sortira de la boucle au prochain passage car la condition sera fausse.

    L'appel à la méthode close() devra être fait manuellement. Toutefois tu peux mettre en place un garde-fou via finalize() :
    PS : Et si tu utilises Java 5 ou plus, tu pourrais te tourner vers les BlockingQueue pour "passer" les actions à ton thread : c'est plus simple que les wait/notify
    Merci, j'avais un peu la même chose mais en + compliqué (avec un champ killer et un notify au lieu de interrupt), et je ne connaissais pas les BlockingQueue
    A+

  17. #17
    Membre expérimenté Avatar de hydraland
    Profil pro
    Développeur Java
    Inscrit en
    Mai 2006
    Messages
    179
    Détails du profil
    Informations personnelles :
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Java

    Informations forums :
    Inscription : Mai 2006
    Messages : 179
    Par défaut
    Salut,

    J'ai fait un petit code à l'arrache (Merci adiGuba ). Il devrait t'aider à résoudre ton problème.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
     
    package testH;
    import java.lang.ref.ReferenceQueue;
    import java.lang.ref.WeakReference;
     
    public class DDE {
     
    	static MyThread thread;
     
    	public DDE()
    	{
    		final ReferenceQueue<DDE> queue = new ReferenceQueue<DDE>();
    		new PoolThread(queue).start(); //Lancement du thread qui test la suppression de l'objet
     
    		thread = new MyThread(new WeakReference<DDE>(this, queue));
    		thread.start();//Lancement du thread de traitement
    	}
     
    	public void print()
    	{
    		System.out.println("test");
    	}
     
    	public static void main(String[] args) throws InterruptedException
    	{
    		DDE dde = new DDE();
    		Thread.sleep(5000);
    		thread.newAction();
    		dde = null; //suppression de l aréférence
    		System.gc(); //On lance le garbage collector pour supprimer l'objet
    		Thread.sleep(10000); //On attent
    	}
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    /**
     * 
     */
    package testH;
     
    import java.lang.ref.WeakReference;
     
    public class MyThread extends Thread
    {
    	private WeakReference<DDE> ref;
     
    	public MyThread(WeakReference<DDE> ref)
    	{
    		this.ref = ref;
    	}
     
    	public void run()
    	{
    		synchronized(this)
    		{
    			try
    			{
    				while(!Thread.interrupted())
    				{
    					this.wait();
     
    					// notification reçue
    					DDE dde = ref.get();
    					if(dde != null)
    					{
    						//exécution
    						dde.print();
    					}
    					else
    					{
    						//plus de référence on arrête le thread
    						this.close();
    					}
     
    					this.notifyAll();
    				}
    			}
    			catch (InterruptedException e)
    			{
    				// Interruption recu
    				// (on sort du while)
    			}
    		}
    		System.out.println("Arrêt du thread.");
    	}
     
    	public void newAction()
    	{
    		synchronized(this)
    		{
    			this.notifyAll();
    		}
    	}
     
    	public void close()
    	{
    		if (this.isAlive()) {
    			this.interrupt();
    		}
    	}
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    /**
     * 
     */
    package testH;
     
    import java.lang.ref.ReferenceQueue;
     
    public class PoolThread extends Thread
    {
    	private ReferenceQueue<DDE> queue;
    	public PoolThread(ReferenceQueue<DDE> q)
    	{
    		queue = q;
    	}
    	public void run()
    	{
    		try
    		{
    			queue.remove();
    			DDE.thread.close();
    		}
    		catch (InterruptedException e)
    		{
    			e.printStackTrace();
    		}
    	}
    }
    A+
    Hydraland

  18. #18
    Membre averti
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    45
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : Juin 2007
    Messages : 45
    Par défaut
    Bonsoir a tous,

    Moi dans mon application j'ai aussi un thread qui ne doit pas s'arrêter, mais par-contre je voudrais detruire les objets dans ce thread... y a t-il une solution? Merci

  19. #19
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Par défaut
    bobo21: au dela du problème d'arreter ton thread, la référencce à ton instance viens seulement du fait que ton thread est une inner class de ta classe DDE -> le thread a une référence DDE.this due à cette structure. Ca n'a rien à voir avec le fait que ce soit DDE qui l'ai lancé. La solution "propre" pour permettre le GC de DDE indépendement du fonctionnement du thread, c'est simplement de mettre ta classé étendant Thread dans son .java à elle, sans référence à DDE:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public class Toto {
    	Toto() {
    		new MyThread().start();
    	}
     
    public static void main() {
    	Toto t = new Toto();
    		t = null;
    	}
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    public class MyThread extends Thread {
      public void run() {
    		//...
    		}
    }
    blaster681: merci de poser tes questions dans ton propre fil de discussion.

Discussions similaires

  1. [JVM] Java 5 et Garbage Collector(Parralèle)
    Par ssaunois dans le forum Général Java
    Réponses: 6
    Dernier message: 28/11/2005, 23h42
  2. [JVM]Garbage collector
    Par godik dans le forum Général Java
    Réponses: 5
    Dernier message: 07/10/2005, 09h12
  3. JPanel et Garbage Collector
    Par tck-lt dans le forum Agents de placement/Fenêtres
    Réponses: 9
    Dernier message: 25/07/2005, 18h03
  4. [JVM] les objets et le Garbage collector
    Par Kurdran dans le forum Général Java
    Réponses: 7
    Dernier message: 02/06/2005, 16h57
  5. [Language]Garbage collector
    Par GETah dans le forum Langage
    Réponses: 2
    Dernier message: 23/03/2005, 15h18

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo