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 :

[Timer, Thread.sleep()] Problème pour attendre avant de faire un traitement


Sujet :

Java

  1. #1
    Membre du Club
    Inscrit en
    Mai 2008
    Messages
    187
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 187
    Points : 51
    Points
    51
    Par défaut [Timer, Thread.sleep()] Problème pour attendre avant de faire un traitement
    Bonjour,
    J'ai une classe Java qui contrôle un affichage d'affiches, il est trop complexe d'expliquer tout le projet mais je vous expose uniquement mon problème : en gros j'ai 2 attributs entiers (qui peuvent prendre comme valeur 1, 2 ou 3) et je dois pouvoir modifier les valeurs de ces 2 attributs au cours du temps de la façon suivante :

    Cycle entierUn : 1 (attendre 5secondes) 2 (attendre 15sec) 3 (attendre 40sec) ... et puis le cycle recommence depuis le début.

    Cycle entierDeux: 1(attendre 35 secondes) 2 (attendre 20sec) 3 (attendre 5 secondes) ... et puis le cycle recommence depuis le début.

    Les deux cylces ont donc une durée totale de 60secondes et commencent en même temps.

    Je pensais donc faire de la façon suivante :
    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
     
    ....
    int un1 = 5, int un2 = 15, int un3 = 40;
    int deux1 = 35, int deux2 = 20, int deux3 = 5; 
    boolean fonctionne = true; 
    ....
    public void cycleEntierUn() {
                while (fonctionne) {
                    entierUn = 1;
                    sleep(un1);
                    entierUn = 2;
                    sleep(un2);
                    entierUn = 3;
                    sleep(un3);
                }
    }
     
    public void cycleEntierDeux() {
                while (fonctionne) {
                    entierDeux = 1;
                    sleep(deux1);
                    entierDeux = 2;
                    sleep(deux2);
                    entierDeux = 3;
                    sleep(deux3);
                }
    }
     
    private void sleep(int sec) {
            try {
                Thread.sleep(sec * 1000);
            } catch (InterruptedException ex) {}
    }
     
    public void modifieUn2() {
            ... voir plus bas 
    }
    Les deux cycles sont lancés par des thread (pour que les deux cycles soient lancés en même temps) dans une méthode principale :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    new Thread(new Runnable() {
                @Override
                public void run() {
                    cycleEntierUn();
                }
            }).start();
     
    new Thread(new Runnable() {
                @Override
                public void run() {
                    cycleEntierDeux();
                }
            }).start();
    Tout fonctionne très bien mis à part qu'en faisant comme ça je n'arrive pas à écrire le code de ma méthode modifieUn2()...
    En effet cette méthode doit pouvoir remplacer la valeur de l'attribut un2 par 1 (au lieu de 15) uniquement pour un cycle et que le changement soit instantané, donc si au moment ou cette méthode est appelée, on se trouve dans l'exécution de sleep(un2) (détecter qu'on est entrain d'exécuter ce sleep il suffit de vérifier quelle valeur a actuellement entierDeux), le sleep(un2) doit être remplacé durant son exécution par sleep(1) que si le temps restant de sleep(un2) est supérieur à 1... Cela me sembre impossible avec cette manière de procéder... Pourriez-vous m'aider?

  2. #2
    Membre chevronné
    Homme Profil pro
    Directeur technique
    Inscrit en
    Janvier 2007
    Messages
    1 348
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Directeur technique

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 348
    Points : 1 787
    Points
    1 787
    Par défaut
    Tu pourrais utiliser la méthode interrupt pour "réveiller" le Thread en train d'exécuter le sleep(un2), mais le soucis c'est que tu ne saurais pas détecter si le temps restant est >1.
    Je te propose qqchose comme suit comme évolution
    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
     
    int un1 = 5, int un2 = 1, int un3 = 15;int un4 = 40;
    boolean interruptable = false;
    public void cycleEntierUn() {
                while (fonctionne) {
                    entierUn = 1;
                    sleep(un1);
                    entierUn = 2;
                    sleep(un2);
                    interruptable = true;
                    try {
                      sleep(un3);
                    } catch (InterruptedException e) {
                      //Thread has been interrupted
                    }
                    interruptable = false;
                    entierUn = 3;
                    sleep(un4);
                }
    }
    et
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    Thread thread1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    cycleEntierUn();
                }
            }).start();
    pour que dans ta méthode tu puisse faire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    if (interruptable) {
      thread1.interrupt();
    }

  3. #3
    Membre chevronné
    Inscrit en
    Mai 2006
    Messages
    1 364
    Détails du profil
    Informations forums :
    Inscription : Mai 2006
    Messages : 1 364
    Points : 1 984
    Points
    1 984
    Par défaut
    Tu peux aussi regarder du coté de la synchronisation (je n'aime pas beaucoup les interruptions ):
    méthode wait(long timeout) -> permet de faire un sleep si pas d'appel à notify
    et notify() -> A appeler en cas de modification de l'attribut en cours de wait.

    Un exemple de tuto sur la synchronisation :
    http://rom.developpez.com/java-synchronisation/

    a+

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

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

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 481
    Points : 48 806
    Points
    48 806
    Par défaut
    Citation Envoyé par alex2746 Voir le message
    En effet cette méthode doit pouvoir remplacer la valeur de l'attribut un2 par 1 (au lieu de 15) uniquement pour un cycle
    Vu qu'elle n'a aucune idée d'ou on est dans les cycle, cette méthode devra juste abaisser un flag disant "attention, va falloir passer à 1" et préciser quelle valeur est à passer à un. Le mieux est de tout faire en un, passer un identifiant de null au nom de l'étape à skipper. Il y a d'autres manières de faire.
    Citation Envoyé par alex2746 Voir le message
    et que le changement soit instantané
    Tu dois donc interrompre le sleep, ça peux se faire avec un appel à interrupt() sur le thread en question. Il faudra bien sûr traiter cette interruption dans ta méthode sleep
    Citation Envoyé par alex2746 Voir le message
    (détecter qu'on est entrain d'exécuter ce sleep il suffit de vérifier quelle valeur a actuellement entierDeux)
    Surtout pas, ça c'est de la méthode cochon qui joue sur l'effet de bord

    Citation Envoyé par alex2746 Voir le message
    , le sleep(un2) doit être remplacé durant son exécution par sleep(1) que si le temps restant de sleep(un2) est supérieur à 1
    Et si il est inférieur?

    Voilà une idée de ce à quoi le code pourrait ressembler. Ce n'est pas parfait et il manque le traitement de quelques effets de bord comme deux interruptions d'affilée

    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
     
    private String nextInteruptionName; 
    private void sleep(int sec, String name) {
     
            long debut = System.currentTimeMillis();
            long duree = sec * 1000;
            while (true)
            try {
                if (nextInteruptionName!=null && nextInteruptionName.equals(name)){
                    duree = 1000;
                    nextInteruptionName = null; // clear flag
                }
                long restant = duree - (System.currentTimeMillis()-debut);
                if (restant<1L)
                   return;  // terminé
                Thread.sleep(restant);
            } catch (InterruptedException ex) {
     
            }
    }
     
    public void modifieUn2() {
            nextInteruptionName = "un2"; 
            thread2.interrupt();
    }
     
    public void cycleEntierUn() {
                while (fonctionne) {
                    entierUn = 1;
                    sleep(un1,"un1");
                    entierUn = 2;
                    sleep(un2,"un2");
                    entierUn = 3;
                    sleep(un3,"un3");
                }
    }

  5. #5
    Membre du Club
    Inscrit en
    Mai 2008
    Messages
    187
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 187
    Points : 51
    Points
    51
    Par défaut
    Merci à tous pour votre aide. Il me reste quelques problèmes...

    tchize_, j'ai essayé d'appliquer ta solution et ça a bien fonctionné. Dans le cas où le temps restant est inférieur au temps par lequel on veut le remplacer (supérieur à une seconde), je relance un sleep(restant), sinon c'est un sleep(1000).

    Par contre je dois faire face à un problème que je n'arrive pas à régler : dans le cas où la valeur de un2 a bien été diminuée et remplacé par une seule seconde, l'autre cycle doit également être diminué (du même nombre de secondes que la diminution faite à un2), sinon la synchronisation n'est plus respectée...

    Je voulais donc faire ceci de la façon suivante, mais ça ne fonctionne plus...

    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
     
    private String nextInteruptionNameA;
    private String nextInteruptionNameB;
    private long dureeEnlevee;
     
     
    private void sleep(int sec, String name) {
     
            long debut = System.currentTimeMillis();
            long duree = sec * 1000;
            while (true) {
                try {
                    long restant = duree - (System.currentTimeMillis() - debut);
                    if ((nextInteruptionNameA != null) && (nextInteruptionNameA.equals("un2"))) {
                        duree = 1000;
                        nextInteruptionNameA = null; // clear flag
                    }
     
                    if ((nextInteruptionNameB != null) && (nextInteruptionNameB.equals("deux1"))) {
                        restant = restant - dureeEnlevee;
                        nextInteruptionNameB = null; // clear flag
                    }
                    if (restant < 1L) {
                        return;  // terminé
                    }
                    if (restant < duree){
                        Thread.sleep(restant);
                    } else {
                        dureeEnlevee = restant-duree;
                        Thread.sleep(duree);
                    }
                } catch (InterruptedException ex) {
                }
            }
    }
     
    public void modifieUn2() {
            nextInteruptionNameA = "un2"; 
            thread2.interrupt();
            //vu la sunchronisation dans mon projet, le deuxième cycle sera dans
            // le sleep(deux1), thread1 est le thread qui a lancé le deuxième cycle
            nextInteruptionNameB = "deux1";
            thread1.interrupt();
    }
    Pourriez-vous m'aider? Merci encore!

  6. #6
    Modérateur

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

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 551
    Points : 21 607
    Points
    21 607
    Par défaut
    S'ils doivent être synchronisés les points de départ ne devraient pas être dans des threads différents. La boucle devrait être unique, et elle devrait lancer l'exécution des deux threads et attendre leur fin.

    Il y a d'autres manières de le faire, comme s'attendre l'un l'autre au début de la boucle. Mais c'est plus compliqué et ça n'a pas l'air intéressant.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

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

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

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 481
    Points : 48 806
    Points
    48 806
    Par défaut
    d'accord avec thelevin, si tu veux garder une synchor entre tes thread, il faut n'en avoir qu'un, avec un découpage plus détaillé. Sinon, ils vont se décaler avec le temps suivant le temps nécessaire pour faire leur travail entre les sleeps.

  8. #8
    Membre du Club
    Inscrit en
    Mai 2008
    Messages
    187
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 187
    Points : 51
    Points
    51
    Par défaut
    Je ne comprends pas vraiment comment mettre ton explication en œuvre... Mes méthodes cycleEntierUn et cycleEntierDeux doivent être remplacée par une seule méthode? En sachant que je dois utiliser les attributs qui se trouvent au dessus (un1, un2, un3, deux1, etc) comme temps des sleep je ne vois pas vraiment comment y arriver... Peux tu m'éclairer un peu plus?

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

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

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 481
    Points : 48 806
    Points
    48 806
    Par défaut
    ben si ton but est de faire

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    A               X
                    2s
    3s             
                    Y
    B              
     
     
    5s              7s
     
     
    C
                    Z
    2s              1s
    =10s            =10s
    Tu va devoir adapter ton code. Tu ne peux pas juste lancer deux thread en parallèle et espérer qu'il restent synchrones indéfiniment. Ils ont chacun leur vie .Soit tu fais un seul thread qui est découpé plus finement:


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    A,X
    2s
    Y
    1s
    B
    5s
    C
    1s
    Z
    1s
    Soit tu utilise un barrière pour resynchronizer tes threads:

    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
    private CyclicBarrier cb = new CyclicBarrier(2);
    public void cycleEntierUn() {
                while (fonctionne) {
                    entierUn = 1;
                    sleep(un1);
                    entierUn = 2;
                    sleep(un2);
                    entierUn = 3;
                    sleep(un3);
                    cb.await();
                }
    }
     
    public void cycleEntierDeux() {
                while (fonctionne) {
                    entierDeux = 1;
                    sleep(deux1);
                    entierDeux = 2;
                    sleep(deux2);
                    entierDeux = 3;
                    sleep(deux3);
                    cb.await();
                }
    }
    et tu va devoir te taper la gestion des BrokenBarrierException si jamais tu interrompt un des threads dans la barrière.

  10. #10
    Membre du Club
    Inscrit en
    Mai 2008
    Messages
    187
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 187
    Points : 51
    Points
    51
    Par défaut
    Je comprends le problème...

    Mais si je prends mon exemple du cycle un :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    public void cycleEntierUn() {
                while (fonctionne) {
                    entierUn = 1;
                    sleep(un1);
                    entierUn = 2;
                    sleep(un2);
                    entierUn = 3;
                    sleep(un3);
                }
    }
    L'attribut un1 représente le temps pendant lequel entierUn reste à 1, l'attribut un2 représente le temps pendant lequel entierUn reste à 2, etc. Je n'ai que ces attributs là, je ne dispose d'aucune informations supplémentaire... cela me semble donc pas possible de réaliser les deux cycles en un seul thread... ou je me trompe?

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

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

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 481
    Points : 48 806
    Points
    48 806
    Par défaut
    Citation Envoyé par alex2746 Voir le message
    cela me semble donc pas possible de réaliser les deux cycles en un seul thread... ou je me trompe?
    Heu non, ca veux juste dire que tu dois réfléchir un peu et créer un algo qui fait le découpage en fonction de tes différentes contrainte temporelles. Si j'arrive à le faire en 30 secondes à la main, un programme doit bien être capable de calculer ça.

  12. #12
    Expert confirmé
    Homme Profil pro
    Inscrit en
    Septembre 2006
    Messages
    2 937
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2006
    Messages : 2 937
    Points : 4 358
    Points
    4 358
    Par défaut
    Pensez à Timer et TimerTask plutôt que Thread.sleep().

    (Timer.scheduleAtFixedRate et une gestion de diagramme d'états peuvent très bien résoudre ce problème)

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

Discussions similaires

  1. Probléme pour tuer un Thread
    Par peyo_le_fou dans le forum POSIX
    Réponses: 5
    Dernier message: 04/11/2006, 14h10
  2. [Prbl] Thread(image ne s'affichant pas avant le thread.sleep
    Par stephane92400 dans le forum Interfaces Graphiques en Java
    Réponses: 4
    Dernier message: 26/06/2006, 11h57
  3. Réponses: 1
    Dernier message: 03/12/2005, 12h24
  4. Thread problème pour l'arreter
    Par rvzip64 dans le forum Langage
    Réponses: 8
    Dernier message: 12/07/2005, 10h51
  5. Fonction du genre delay, sleep, wait pour attendre 1000ms
    Par FrankOVD dans le forum Général JavaScript
    Réponses: 2
    Dernier message: 28/06/2005, 17h17

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