Utiliser un démon                  

Utiliser un démon

Il existe deux sortes de threads :

Quand un thread crée un autre thread, le thread créé a la même nature (utilisateur ou démon) que le thread créateur. La méthode main est lancée comme un thread utilisateur. On peut changer la nature d'un thread par la méthode :
    public void setDaemon(boolean b);

Le programme qui nous sert ici d'exemple doit utiliser un thread démon, le collecteur de mots, pour collecter dans une chaîne de caractères des mots produits par un ensemble de producteurs de mots, qui sont des threads utilisateurs.

Le collecteur de mots dispose d'un attribut mot (de type String) pouvant contenir un mot et un second attribut (de type StringBuilder) lui servant à collecter les mots.

Dans sa méthode run, un producteur répète trois fois les opérations suivantes :

Dans sa méthode run, le collecteur attend (grâce à la méthode wait) qu'un producteur de mots en ait produit un, ajoute le nouveau mot à la fin de la chaîne lui servant à collecter les mots, écrit cette chaîne à l'écran puis effectue une notification à l'attention d'un producteur qui attendrait de déposer un mot, pour que celui-ci sache que le collecteur n'est plus occupé.
import java.util.Random;

class Generateur {
	static Random alea = new Random();
}

class Collecteur extends Thread {
	private StringBuilder texte = new StringBuilder();
	private boolean travailAFaire = false;
	private String mot;

	Collecteur() {
		setDaemon(true);
	}

	public String getMot() {
		return mot;
	}

	public void setMot(String mot) {
		this.mot = mot;
	}
	
	public boolean isTravailAFaire() {
		return travailAFaire;
	}

	public void setTravailAFaire(boolean travailAFaire) {
		this.travailAFaire = travailAFaire;
	}

	public synchronized void run() {
		try {
			while(true) {
				while(!travailAFaire) wait();
				texte.append(mot);
				System.out.println(texte);
				travailAFaire = false;
				notifyAll();
			}
		}
		catch(InterruptedException e) {}
	}
}

class ProducteurMots extends Thread {
	private Collecteur collecteur;
	private String mot;

	ProducteurMots(Collecteur collecteur, String mot) {
		this.collecteur = collecteur;
		this.mot = mot;
	}

	public void run() {
		try {
			for (int i = 0; i < 3; i++) {
				sleep(Math.abs(Generateur.alea.nextInt()) % 10);
				synchronized(collecteur) {
					while (collecteur.isTravailAFaire()) collecteur.wait();
					collecteur.setMot(mot);
					collecteur.setTravailAFaire(true);
					collecteur.notifyAll();
				}
			}

		// Ce qui suit evite que le programme ne se termine 
		// avant que le demon n'ait ecrit sa derniere ligne
			synchronized(collecteur) {
				while(collecteur.isTravailAFaire()) collecteur.wait();
			}
		}
		catch(InterruptedException e) {
			e.printStackTrace();}
	}
}

class Assemble {
	public static void main(String[] arg) {
		Collecteur collecteur = new Collecteur();

		collecteur.start();
		new ProducteurMots(collecteur, "soleil ").start();
		new ProducteurMots(collecteur, "lune ").start();
	}
}
À l'exécution, on a obtenu :
soleil 
soleil lune 
soleil lune soleil 
soleil lune soleil soleil 
soleil lune soleil soleil lune 
soleil lune soleil soleil lune lune 
Le fichier source
setDaemon(true); : on demande que le thread concerné soit un démon.
while(true) : cette boucle ne sera pas répétée indéfiniment car, lorsque tous les threads utilisateurs sont achevés, le thread démon s'arrête à son tour.
texte.append(mot); : la méthode de la classe permet d'ajouter la chaîne de caractères indiquée en argument (ici mot) à la chaîne concernée (ici "texte").
© Irène Charon, Télécom ParisTech 2011