<<<M1 - UE2

1 Rappels programmation concurrente et threads

Note : on pourra se référer à l'API JavaSE 7 pour plus de détails.

1.1. Thread

En informatique, un thread d'exécution (ou plus simplement thread) est la plus petite partie qui peut être traitée par un système d'exploitation lors de l'exécution. L'une des fonctionnalités de l'OS (Operating System) consiste à réaliser l'ordonnancement des processus à exécuter.

On qualifie généralement un thread de processus léger car il est contenu dans un processus.

Un processus (ou plus simplement programme en exécution) peut également être composé de plusieurs threads qui s'exécutent de manière concurrente. Les threads d'un même processus partagent des ressources (comme de la mémoire ou des canaux d'entrée / sortie).

Lorsque l'on programme avec Java, la gestion des threads est simplifiée : un programme, c'est à dire une classe dotée de la méthode main, possède un thread d'exécution.

1.1.1. Exemple fork en C


Warning: file_get_contents(ens/m1/info/ue2/forkit.c): failed to open stream: No such file or directory in /home/jeanmichel.richer/public_html/html_business.php on line 482
  1.  

La commande top indique bien deux processus.

3129 richer    20   0  1988   60    0 R   22  0.0   0:01.58 forkit.exe
3128 richer    20   0  1988  284  228 R   21  0.0   0:01.54 forkit.exe

1.1.2. création d'un thread

Pour créer d'autres threads au sein du programme principal, on définit des classes qui vont :

Dans les deux cas, il faudra définir la méthode run qui contient les instructions exécutées par le thread.


class MyRunnable extends MyClass implements Runnable {
	public void run() {
		// code to execute
	}
}

class MyThread extends Thread {
	public void run() {
		// code to execute
	}
}

Un thread peut être doté d'un nom (constructeur ou setName()) et/ou rattaché à une groupe de threads (ThreadGroup - cf plus loin dans le cours).


class MyThread extends Thread {

	public MyThread(String name) {
		super(name);
	}
	
	public void run() {
		while (true) {
			System.err.println("hello world !");
		}
	}
}

1.1.3. lancement de l'exécution d'un thread

On lance l'exécution du thread par appel de ma méthode start


class MyProgram {

	public static void main(String args[]) {
		MyThread thread = new MyThread("a thread");
		thread.start();
	}
	
}

ou encore :


class MyProgram {

	public static void main(String args[]) {
		new Thread(new MyRunnable()).start();
	}
	
}

Le programme ne terminera que lorsque le thread aura terminé son exécution.

Voici un exemple :


Warning: file_get_contents(ens/m1/info/ue2/Main.java): failed to open stream: No such file or directory in /home/jeanmichel.richer/public_html/html_business.php on line 482
  1.  

La commande top indique un seul processus.

 3843 richer    20   0 1223m  31m 7336 S   59  0.4   0:04.51 java

1.1.4. états d'un thread

thread states

On peut connaître l'état d'un thread en appelant la méthode Thread.State getState().

1.1.5. suspendre et reprendre l'exécution d'un thread

Il existe plusieurs moyens pour suspendre temporairement l'exécution d'un thread.

1.1.6. synchronisation des threads

Il existe plusieurs niveaux de synchronisation pour les threads.


Warning: file_get_contents(ens/m1/info/ue2/JoinExample.java): failed to open stream: No such file or directory in /home/jeanmichel.richer/public_html/html_business.php on line 448
  1.  

Le résultat de l'exécution est par exemple :

thread0:1
thread1:1
thread2:1
thread1:2
thread0:2
thread2:2
thread2:3
thread1:3
thread2:4
thread0:3
thread1:4
thread0:4
JOIN HERE

1.1.7. priorités d'un thread

Chaque thread possède une priorité d'exécution, héritée par défaut de son thread parent. On peut cependant modifier la priorité d'un thread grâce à void setPriority(int newPriority). Celle-ci varie entre :

On obtient la priorité d'un thread grâce à int getPriority().

1.1.8. groupes de threads

Il est parfois intéressant de regrouper les threads par groupes. Sur l'exemple suivant on crée deux groupes de threads, le groupe g1 continuera à s'exécuter alors que g2 sera interrompu par le thread t3. Une exception InterruptedException est levée car les threads de g2 sont interrompus alors qu'ils sont dans l'état waiting engendré par l'instruction sleep


Warning: file_get_contents(ens/m1/info/ue2/ThreadGroups.java): failed to open stream: No such file or directory in /home/jeanmichel.richer/public_html/html_business.php on line 448
  1.  

Le résultat de l'exécution est par exemple :

g1.t1-1 running
g1.t1-4 running
g2.t2-1 running
g1.t1-3 running
g2.t2-2 running
g2.t2-4 running
g1.t1-2 running
g2.t2-3 running
g1.t1-1 running
g1.t1-4 running
g1.t1-3 running
g2.t2-1 running
g2.t2-4 running
g1.t1-2 running
g2.t2-2 running
g2.t3:active = 0
g2.t2-3 running
g2.t2-1:java.lang.InterruptedException: sleep interrupted
g2.t2-4:java.lang.InterruptedException: sleep interrupted
g2.t2-3:java.lang.InterruptedException: sleep interrupted
g2.t2-2:java.lang.InterruptedException: sleep interrupted
g1.t1-1 running
g1.t1-4 running
g1.t1-3 running
g1.t1-2 running

1.2. Programmation concurrente

Le principe de la programmation concurrente consiste à faire interagir plusieurs threads pour accomplir une tâche.

On peut distinguer deux approches :

Exemple 1 : on désire réaliser le calcul de la somme des évaluations d'une fonction f(x), pour différentes valeurs de x, sur l'intervalle [x1, x2] mais le calcul de f(x) prend du temps. Les calculs étant indépendants on décide de multithreader l'application. On utilisera par exemple k threads qui se répartiront la tâche : feront les calculs en parallèle et reporteront leurs résultats à l'application principale.

Exemple 2 : on souhaite résoudre un problème d'optimisation combinatoire et on crée plusieurs threads qui recherchent la meilleure solution possible et échangent de l'information : exploration, intensification.