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

Concurrence et multi-thread Java Discussion :

Qu'est-ce que je n'ai pas compris dans les threads ?


Sujet :

Concurrence et multi-thread Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé

    Profil pro
    Inscrit en
    Janvier 2004
    Messages
    469
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2004
    Messages : 469
    Par défaut Qu'est-ce que je n'ai pas compris dans les threads ?
    Bonjour,

    J'ai lu plusieurs articles sur les Threads. J'avais cru comprendre que lorsqu'un thread quitte sa méthode run il prend l'état TERMINATED.
    Aussi est-ce que quelqu'un peut m'expliquer ce qui ne marche pas dans le code suivant ?
    La classe interface graphique avec une méthode main(). On lance le thread avec le bouton play, on l'arrête avec le bouton stop (rien de bien original donc)
    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
    67
    68
    69
    70
    71
    72
    73
    74
     
    public class Essai extends JFrame  implements ActionListener, ObservateurFil
    {
    	private Fil monThread;
    	private JButton stop = new JButton("Stop") ;
    	private JButton play = new JButton("Play");
    	private boolean boucle = false;
     
    	public Essai ()
    	{
    		super("test Thread");
    		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    		monThread = new Fil();
    		monThread.ajouteObservateur(this);
    		JPanel boutons = new JPanel();
    		boutons.setLayout(new FlowLayout());
    		play.setEnabled(true);
    		stop.setEnabled(false);
    		play.addActionListener(this);
    		stop.addActionListener(this);
    		boutons.add(stop);
    		boutons.add(play);
    		this.add(boutons,BorderLayout.SOUTH);
    		pack();
    		setLocationRelativeTo(null);
    		setVisible(true);
    	}
     
    	@Override
    	public void actionPerformed(ActionEvent e) 
    	{
    		if (e.getSource() == stop) stop();
    		else if (e.getSource() == play) play();
    	}
     
    	private void play() 
    	{
    		System.out.println("j'ai cliqué sur play : " + monThread.getState());
    		if (monThread.getState() == State.TERMINATED) 
    		{
    			monThread = new Fil();
    		}
    		stop.setEnabled(true);
    		play.setEnabled(false);
    		monThread.setEtat(EtatFil.PLAY);
    		if (monThread.getState() == State.NEW) monThread.start();
    	}
     
    	private void stop() 
    	{
    		stop.setEnabled(false);
    		play.setEnabled(true);
    		monThread.setEtat(EtatFil.STOP);
    		System.out.println("fin du Thread " + monThread.getState());
    	}
     
    	@Override
    	public void finThread() 
    	{
    		stop();
    		if (boucle) play();
    	}
     
    	public static void main(String ...args) 
    	{
    		javax.swing.SwingUtilities.invokeLater(new Runnable() 
    	 	{
    			public void run() 
    	     	{
    				new Essai(); 
    	     	}
    	 	});
    	}
    }
    La classe qui représente un Thread. Au lancement du thread, on stocke l'heure de début du thread, puis on lance une boucle sans fin qui s'arrête soit par l'appui sur STOP soit parce que le temps est écoulé.
    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
     
    public class Fil  extends Thread
    {
    	private EtatFil etat;
    	private ObservateurFil observateur;
    	private List<ObservateurFil> observateurs = new ArrayList<ObservateurFil>();
     
    	public Fil()
    	{
    		super("Test Thread");
    		etat = EtatFil.STOP;
    	}
     
    	public void ajouteObservateur(ObservateurFil of)
    	{
    		this.observateur = of;
    	}
     
    	public void run()
    	{
    		long debut = System.currentTimeMillis();
    		int m = -1;
    		while(true)
    		{
    			if (etat == EtatFil.STOP || etat == EtatFil.EOM)
    			{
    				break;
    			}
    			if(etat == EtatFil.PLAY)
    			{
    				int t = (int) ((System.currentTimeMillis() - debut)/1000);
    				if (t != m) 
    				{
    					m = t;
    					System.out.println(m);
    				}
    				//on arrive à la fin du comptage, on arrête
    				if (m > 4)
    				{
    					etat = EtatFil.EOM;
    				}
    			}
    		}
    		observateur.finThread();
    	}
     
    	public void setEtat(EtatFil e) 
    	{
    		etat = e;
    	}
    }
    Une énumération des divers états du fil
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    public enum EtatFil 
    {
        STOP, PAUSE , PLAY, EOM;
    }
    L'interface pour les observateurs
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    public interface ObservateurFil 
    {
        public void finThread();
    }
    Quand je clique sur PLAY puis sur STOP j'ai cela dans la console.

    j'ai cliqué sur play : NEW
    0
    1
    2
    fin du Thread RUNNABLE
    fin du Thread RUNNABLE

    J'ai deux questions :
    pourquoi ai-je deux fois la ligne "fin du Thread RUNNABLE" ?
    pourquoi l'état n'est pas TERMINATED ?

  2. #2
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 582
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 582
    Par défaut
    Hello,

    Citation Envoyé par Patrice Henrio Voir le message
    Qu'est-ce que je n'ai pas compris dans les threads ?
    La synchronisation des données.

    Citation Envoyé par Patrice Henrio Voir le message
    pourquoi ai-je deux fois la ligne "fin du Thread RUNNABLE" ?
    Il est affiché à chaque fois que tu cliques sur le bouton et à chaque fois que le thread appelle finThread(), ce qui fait donc deux fois.
    C'est ton code, c'est toi qui l'as fait comme ça.

    Citation Envoyé par Patrice Henrio Voir le message
    pourquoi l'état n'est pas TERMINATED ?
    Le thread est toujours en plein dans sa méthode run(), dans les deux cas.
    Si tu avais utilisé la synchronisation et que donc ta tentative d'arrêter le thread marchait, il serait possible, bien que peu probable, que le deuxième affichage dise TERMINATED, le thread s'étant bel et bien terminé entre la demande d'arrêt et la demande de son état actuel.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  3. #3
    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,

    Citation Envoyé par Patrice Henrio Voir le message
    pourquoi ai-je deux fois la ligne "fin du Thread RUNNABLE" ?
    Parce que le code de la méthode stop() est exécuté deux fois.
    • Une fois via actionPerformed(), lorsque tu cliques sur le bouton.
    • Une fois via finThread() via l'observateur, lorsque le code du thread se termine.




    Citation Envoyé par Patrice Henrio Voir le message
    pourquoi l'état n'est pas TERMINATED ?
    Parce qu'il n'est pas encore terminé !

    Tu ne fais que changer un de ses attributs. Rien ne garantie que le code du thread est déjà fini...



    Sinon une remarque : Tu fais une boucle active pour attendre 1s !
    Un Thread.sleep() serait plus approprié... parce que sinon tu bouffes tout le CPU pour rien !


    a++

  4. #4
    Membre éclairé

    Profil pro
    Inscrit en
    Janvier 2004
    Messages
    469
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2004
    Messages : 469
    Par défaut
    Tout d'abord merci de vos réponses.
    En tout premier lieu vous vous doutez bien que ce n'est qu'un modèle et que si je n'ai pas utilisé sleep(1000) pour attendre une seconde c'est que justement dans l'utilisation que je vais en faire je ne veux pas attendre une seconde sans rien faire. De plus sleep est entouré d'un try catch qui simplifie le problème car il me suffit alors d'appeler interrupt pour que ça marche comme je veux.

    Pour les deux appels j'aurai du en effet trouvé moi-même la raison. Ceci étant ce n'est pas bien grave car en définitive le but était seulement de trouver l'état dans lequel était le thread.

    Par contre pour la synchronisation ... c'est sûr que j'ai pas bien compris. J'ai pourtant lu plusieurs articles parlant de cela.

    Dans mon cas je pense que c'est etat qui devrait être synchronisé, mais je ne vois pas comment m'y prendre ?

  5. #5
    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
    Citation Envoyé par Patrice Henrio Voir le message
    Par contre pour la synchronisation ... c'est sûr que j'ai pas bien compris. J'ai pourtant lu plusieurs articles parlant de cela.

    Dans mon cas je pense que c'est etat qui devrait être synchronisé, mais je ne vois pas comment m'y prendre ?
    Deux solutions :
    • Soit tu utilises des bloc synchronized à chaque fois que tu lis/modifies l'attribut "etat".
    • Soit tu le déclares en volatile, ce qui devrait être amplement suffisant...



    a++

  6. #6
    Membre éclairé

    Profil pro
    Inscrit en
    Janvier 2004
    Messages
    469
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2004
    Messages : 469
    Par défaut
    Citation Envoyé par adiGuba Voir le message
    Deux solutions :
    • Soit tu utilises des bloc synchronized à chaque fois que tu lis/modifies l'attribut "etat".
    • Soit tu le déclares en volatile, ce qui devrait être amplement suffisant...



    a++
    J'ai donc essayé de déclarer etat en volatile mais ça n'a rien changé

    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
     
    public class Fil  extends Thread
    {
    	volatile EtatFil etat;
    	private ObservateurFil observateur;
    	// les écouteurs qui seront informés des changements d'état
    	private List<ObservateurFil> observateurs = new ArrayList<ObservateurFil>();
     
    	public Fil()
    	{
    		super("Test Thread");
    		etat = EtatFil.STOP;
    	}
     
    	public void ajouteObservateur(ObservateurFil of)
    	{
    		this.observateur = of;
    	}
     
    	/**
             * la boucle principale.
             * Actions selon l'état du lecteur
             */
    	public void run()
    	{
    		long debut = System.currentTimeMillis();
    		int m = -1;
    		while(true)
    		{
    			if (etat == EtatFil.STOP || etat == EtatFil.EOM)
    			{
    				break;
    			}
    			if(etat == EtatFil.PLAY)
    			{
    				int t = (int) ((System.currentTimeMillis() - debut)/1000);
    				if (t != m) 
    				{
    					m = t;
    					System.out.println(m);
    				}
    				//on arrive à la fin du comptage, on arrête
    				if (m > 4)
    				{
    					etat = EtatFil.EOM;
    				}
    			}
    		}
    		observateur.finThread(etat);
    	}
     
    	public void setEtat(EtatFil e) 
    	{
    		etat = e;
    	}
    }
    Et après un play/stop
    j'ai cliqué sur play : NEW
    0
    1
    fin du Thread RUNNABLE
    fin du Thread RUNNABLE

    Je vais tester la première solution

  7. #7
    Membre éclairé

    Profil pro
    Inscrit en
    Janvier 2004
    Messages
    469
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2004
    Messages : 469
    Par défaut
    Citation Envoyé par adiGuba Voir le message
    Deux solutions :
    • Soit tu utilises des bloc synchronized à chaque fois que tu lis/modifies l'attribut "etat".
    • Soit tu le déclares en volatile, ce qui devrait être amplement suffisant...



    a++
    J'ai utilisé la première méthode avec synchronized, sans succès

    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
     
    public class Fil  extends Thread
    {
    	private EtatFil etat;
    	private ObservateurFil observateur;
    	// les écouteurs qui seront informés des changements d'état
    	private List<ObservateurFil> observateurs = new ArrayList<ObservateurFil>();
     
    	public Fil()
    	{
    		super("Test Thread");
    		etat = EtatFil.STOP;
    	}
     
    	public void ajouteObservateur(ObservateurFil of)
    	{
    		this.observateur = of;
    	}
     
    	/**
             * la boucle principale.
             * Actions selon l'état du lecteur
             */
    	public void run()
    	{
    		long debut = System.currentTimeMillis();
    		int m = -1;
    		while(true)
    		{
    			synchronized(etat)
    			{
    				if (etat == EtatFil.STOP || etat == EtatFil.EOM) break;
     
    				if(etat == EtatFil.PLAY)
    				{
    					int t = (int) ((System.currentTimeMillis() - debut)/1000);
    					if (t != m) 
    					{
    						m = t;
    						System.out.println(m);
    					}
    					//on arrive à la fin du comptage, on arrête
    					if (m > 4) etat = EtatFil.EOM;
    				}
    			}
    		}
    		observateur.finThread(etat);
    	}
     
    	public void setEtat(EtatFil e) 
    	{
    		etat = e;
    	}
    }
    Et toujours la même réponse :
    j'ai cliqué sur play : NEW
    0
    1
    2
    fin du Thread RUNNABLE
    fin du Thread RUNNABLE

  8. #8
    Membre éclairé

    Profil pro
    Inscrit en
    Janvier 2004
    Messages
    469
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2004
    Messages : 469
    Par défaut
    J'ai fini par régler le problème (presque).
    Tout venait effectivement, comme on me l'avait indiqué dés le début, du fait que par mon code je passais deux fois dans la méthode finThread().
    J'ai ainsi modifié ma classe Fil et ma classe Essai
    La classe Essai
    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
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
     
    public class Essai extends JFrame  implements ActionListener, ObservateurFil
    {
    	private Fil monThread;
    	private JButton stop = new JButton("Stop") ;
    	private JButton play = new JButton("Play");
    	private boolean boucle = false;
     
    	public Essai ()
    	{
    		super("test Thread");
    		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    		monThread = new Fil();
    		monThread.ajouteObservateur(this);
    		JPanel boutons = new JPanel();
    		boutons.setLayout(new FlowLayout());
    		play.setEnabled(true);
    		stop.setEnabled(false);
    		play.addActionListener(this);
    		stop.addActionListener(this);
    		boutons.add(stop);
    		boutons.add(play);
    		this.add(boutons,BorderLayout.SOUTH);
    		pack();
    		setLocationRelativeTo(null);
    		setVisible(true);
    	}
     
    	@Override
    	public void actionPerformed(ActionEvent e) 
    	{
    		if (e.getSource() == stop) stop();
    		else if (e.getSource() == play) play();
    	}
     
    	private void play() 
    	{
    		System.out.println("j'ai cliqué sur play : " + monThread.getState());
    		if (monThread.getState() == State.TERMINATED) 
    		{
    			monThread = new Fil();
    		}
    		stop.setEnabled(true);
    		play.setEnabled(false);
    		monThread.setEtat(EtatFil.PLAY);
    		if (monThread.getState() == State.NEW) monThread.start();
    	}
     
    	private void stop() 
    	{
    		stop.setEnabled(false);
    		play.setEnabled(true);
    		monThread.setEtat(EtatFil.STOP);
    		try 
    		{
    			Thread.sleep(200);
    		} catch (InterruptedException e) 
    		{
    			e.printStackTrace();
    		}
    		System.out.println("fin du Thread " + monThread.getState());
    	}
     
    	@Override
    	public void finThread() 
    	{
    		stop.setEnabled(false);
    		play.setEnabled(true);
    		try 
    		{
    			Thread.sleep(200);
    		} catch (InterruptedException e) 
    		{
    			e.printStackTrace();
    		}
     
    		System.out.println("fin du Thread " + monThread.getState());		
    		if (boucle) play();
    	}
     
    	public static void main(String ...args) 
    	{
    		javax.swing.SwingUtilities.invokeLater(new Runnable() 
    	 	{
    			public void run() 
    	     	{
    				new Essai(); 
    	     	}
    	 	});
    	}
     
    }
    Donc
    finThread() ne nécessite plus de passer un état.
    stop() attend 20 ms avant d'afficher l'état du thread ce qui doit lui laisser le temps de se terminer.
    La classe Fil
    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
     
    public class Fil  extends Thread
    {
    	private EtatFil etat;
    	private ObservateurFil observateur;
     
    	public Fil()
    	{
    		super("Test Thread");
    		etat = EtatFil.STOP;
    	}
     
    	public void ajouteObservateur(ObservateurFil of)
    	{
    		this.observateur = of;
    	}
     
    	public void run()
    	{
    		long debut = System.currentTimeMillis();
    		int m = -1;
    		while(true)
    		{
    				if (etat == EtatFil.STOP ) break;
     
    				if(etat == EtatFil.PLAY)
    				{
    					int t = (int) ((System.currentTimeMillis() - debut)/1000);
    					if (t != m) 
    					{
    						m = t;
    						System.out.println(m);
    					}
    					if (m > 4) 
    					{
    						observateur.finThread();
    						break;
    					}
    				}
    			}
    		}
    	}
     
    	public void setEtat(EtatFil e) 
    	{
    		etat = e;
    	}
    }
    Maintenant le STOP fonctionne comme je le souhaite par contre pour la fin du thread il y a un problème minime.
    A la fin du thread celui-ci est encore dans l'état RUNNABLE mais dés que je clique sur PLAY il se retrouve bien dans l'état TERMINATED

  9. #9
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 582
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 582
    Par défaut
    Citation Envoyé par Patrice Henrio Voir le message
    car en définitive le but était seulement de trouver l'état dans lequel était le thread.
    Hummm... Pourquoi faire ?
    En principe c'est juste pour donner quelques infos de monitoring, c'est pas très important pour faire les choses elles-mêmes.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  10. #10
    Membre éclairé

    Profil pro
    Inscrit en
    Janvier 2004
    Messages
    469
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2004
    Messages : 469
    Par défaut
    Citation Envoyé par thelvin Voir le message
    Hummm... Pourquoi faire ?
    En principe c'est juste pour donner quelques infos de monitoring, c'est pas très important pour faire les choses elles-mêmes.
    Le but est d'avoir une interface qui gère un thread via deux boutons PLAY et STOP, mais le thread lui-même doit pouvoir communiquer avec l'interface soit pour recevoir les ordres de l'interface, soit pour indiquer à l'interface que le thread a fini son travail.
    C'est je pense un problème très classique mais je n'y arrive pas, ou plutôt je ne comprends pas tout. En effet dans l'exemple cité, si après STOP j'appuie de nouveau sur PLAY, le thread est bien dans l'état TERMINATED alors que le STOP indiquait un état RUNNABLE

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [Smarty] Pourquoi le php n'est pas recommandé dans les templates ?
    Par SlymDesign dans le forum Bibliothèques et frameworks
    Réponses: 5
    Dernier message: 10/10/2007, 11h21
  2. Est-ce que je peux utiliser certain symbole dans le nom de dossier
    Par pierrot10 dans le forum Balisage (X)HTML et validation W3C
    Réponses: 2
    Dernier message: 24/09/2007, 20h45
  3. [DOM] Qu'est-ce que IE7 ne comprend pas ?
    Par MikeV dans le forum Général JavaScript
    Réponses: 5
    Dernier message: 14/08/2007, 22h38
  4. Réponses: 3
    Dernier message: 26/04/2007, 11h50
  5. qu'est ce que vous n'accepterez pas de votre boss ?
    Par gloglo dans le forum Emploi
    Réponses: 13
    Dernier message: 22/11/2006, 00h48

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