[Java] debutant | thread | wait() notify()

Salut!

Question débile mais question quand même j’aimerai savoir à quoi ça sert de mettre un thread en attente avec wait() et de le reveiller apres. Me renvoyer pas vers la doc please j’en ai déjà lu pas mal.

je m’explique sur un exemple

vous avez une classe ressource, une classe lecteur et une classe ecrivain, un lecteur lit la ressource, un ecrivain ecrit la ressource mais ils ne peuvent pas le faire tous les deux en meme temps!

j’ai donc entre autre ça comme méthode

public synchronized void requeteEcriture(){
try{
while(unLecteurActif) {
wait();
}
unEcrivainActif = true;
}catch (InterruptedException e){}

}

public void run() {
try {
cptE.requeteEcriture();
// on fait l’ecriture

...

En gros dans le run de la classe ecrivain, il demande d’abord à la ressource si il y a un lecteur qui lit la ressource ou pas. Et tant qu un lecteur est actif on attent et on ‘endort’ le thread.

j’aimerais savoir à quoi cela sert d’endormir le thread étant donné que même sans le wait tant qu’il y aura un lecteur actif on restera dans la boucle et le thread ne pourra pas continuer de s’executer ?? j’ai bien dans l’idée que en endormant le thread on libere un peu le processeur, mais bon pour ce que je fais c’est dérisoire. quelqu’un peut m’expliquer ? car j’ai l’impression que j’ai raté une partie du cours :lol:

de plus je viens de tester avec le wait et c’est bizarre il ne fait pas la suite des instruction apres le wait je croyais que le wait bloquait le thread pas la boucle! :??:

merci :slight_smile:

EDIT : pb résolu

Le wait ne fait pas que s’endormir, il permet aussi aux autres threads de passer dans ton bloc synchronized. D’ailleurs, au passage, c’est très mauvais de synchroniser sur l’objet courant (j’ai vu ça en cours, maintenant me souviens plus de la raison exact) et en utilisant la syntaxe synchronized sur les méthodes.

Un exemple concrêt :

J’ai 15 threads qui font un travail donné.
Je veux que quand ce travail est fini elle en fasse un autre dépendant d’un calcul que fera la dernière thread.

Ca donne ça:

synchronized(o) {
  if ( isLastThread() ) {
    doSoWork();
    o.notifyAll();
  } else while ( workNotDone() ) o.wait();
}

Y a plein d’exemples, donc bon :slight_smile:

Les wait/notify c’est assez délicat à maîtriser, il faut bien prévoir tout les cas d’entrelacement de code entre tes Thread. D’ailleurs pour éviter les problèmes, la doc de sun préconise d’utiliser notifyall plutôt que notify pour éviter que des Threads ne restent bloqués (donc en dead-lock) (ce qui est un poil stupide puisque ça ne fait pas la même chose)

Si tu peux te contenter de synchroniser tes données entre tes Threads, c’est plus sûr et plus facile.

Par contre tu peux avoir besoin qu’un Thread attende explicitement la fin du traitement d’un autre Thread avant de poursuivre un traitement. ça dépend des algo utilisés: on peut prendre l’exemple bateau d’une multiplication de matrice parallèle (qui ne doit pas être optimal en java): chaque Thread lance la multiplication d’un bloc en parallèle, et attend la fin des autres Thread avant de passer à la multiplication suivante…

Un exemple assez bien concus de l’utilisation de ces wait/notify est l’implémentation d’un sémaphore:


/**
 * Semaphore is a straightforward implementation of the well-known
 * synchronization primitive. Its counter can be initialized to any
 * nonnegative value -- by default, it is zero.
 */
public class Semaphore {
    private int counter;

    public Semaphore() {
        this(0);
    }

    public Semaphore(int i) {
        if (i < 0) throw new IllegalArgumentException(i + " < 0");
        counter = i;
    }

    /**
     * Increments internal counter, possibly awakening a thread
     * wait()ing in acquire().
     */
    public synchronized void release() {
        if (counter == 0) {
            this.notify();
        }
        counter++;
    }

    /**
     * Decrements internal counter, blocking if the counter is already
     * zero.
     *
     * @exception InterruptedException passed from this.wait().
     */
    public synchronized void acquire() throws InterruptedException {
        while (counter == 0) {
            this.wait();
        }
        counter--;
    }

}

Merci pour vos réponses :slight_smile:

Après quelques dizaines d’heures dessus ça va beaucoup mieux :smiley:

En effet j’ai utilisé notifyAll plutot que notify et ça a l’air de pas marcher trop mal comme ça :slight_smile: Je dois pas maitriser encore tout à fait mon sujet mais bon j’ai pas trop le temps et ça fait ce que je veux :slight_smile: plusieurs lecteurs peuvent acceder à une ressource en meme temps mais un seul écrivain peut y acceder.

J’ai encore deux petites questions :slight_smile:

Je fais un espece de tchat donc je récuper les flux d’entrée d’une personne et je renvoie vers le flux de sortie d’une autre personne.

le probleme c’est que lorsque une personne écrit, elle ne voit pas ce qu’elle écrit. j’ai bien pensé récuperer le flux d’entrée de ce qu’elle écrite et lui renvoyer directement dans son flux de sortie mais du coup ça l’écrit en double!!

voilà mon bout de code

char charcourant[]=new char[1];
while((_entree.read(charcourant,0,1)!=-1)&&(stop==0))
{
_sortie.write(charcourant[0]);
_sortie.flush();

pourquoi ça l’écrit en double ? :??:

et deuxieme petite question :slight_smile:

Apres avoir récuperer le flux d’entrée d’une personne je l’envoie vers le flux de sortie d’une autre. je fais ça en boucle donc les mots se succedent j’aimerai bien mettre chaque mot à la ligne donc j’ai rajouter un \n apres chaque mot lu. l’ennui c’est que ça me l’affiche comme ça :

ceci
est
un essai

et j’aimerai bien que ça me l’affiche comme ça

ceci
( espace ) est
( espace espace ) un essai

quelqu’un a une idée svp ? :smiley:

mici :slight_smile:

Essaye dans eclipse : si la première ligne est en verte, c’est que c’est qu’à taper l’utilisateur.

En gros : tu as l’entrée utilisateur qui reste, et ton écriture qui s’affiche derrière. Donc rien d’anormal

bah la si je met pas _sortie.write(charcourant[0]); et_sortie.flush();

dans ce bout de code :

char charcourant[]=new char[1];
while((_entree.read(charcourant,0,1)!=-1)&&(stop==0))
{
_sortie.write(charcourant[0]);
_sortie.flush();

et bien quand je rentre un caractere dans la console il ne s’affiche pas :frowning: et si je met ça il s’affiche en double :frowning: :frowning:

je travaille sous éclipse mais j’ai jamais vu de ligne vert :??:

pour ma deuxieme question j’ai trouvé il suffisait de rajouter un \r pour dire retour chariot :slight_smile:

et à propos comment detecter que l’utilisateur à taper un control C ?

merci en tous cas :slight_smile:

Pour le ctrl C, ça envoie un signal en C. Je ne sais pas comment on définit les signaux en java, ceci dit.