Conception et Programmation Orientées Objet
La Programmation concurrente en Java
2A DUT Informatique - Cursus de formation en apprentissage IUT d’Orsay - Université Paris-Saclay - 2021/2022
Présenté par :
Idir AIT SADOUNE
1 Systèmes multitâches
2 Les processus et les threads en Java 3 Quelques méthodes de la classe Thread
4 Gestion des ressources et des sections critiques
2∠34§
1 Systèmes multitâches
2 Les processus et les threads en Java 3 Quelques méthodes de la classe Thread
4 Gestion des ressources et des sections critiques
Systèmes multitâches
Un système multitâches permet d’exécuter plusieurs programmes informatiques en parallèle.
4∠34§
Systèmes multiprocesseurs
• Vrai-parallélisme : les systèmes multiprocesseurs permettent
un parallélisme, où chaque tâche est exécutée par un processeur différent.
Processeur P1 Tâche T1
Processeur P2 Tâche T2
Systèmes monoprocesseur
• Pseudo-parallélisme : les systèmes monoprocesseur permettent
un parallélisme, où toutes les tâches s’exécutent sur le même processeur.
• Systèmes à traitement par lots
Processeur P1 Tâche T1 Tâche T2
• Systèmes à temps partagé
Processeur P1 T1 T2 T1 T2 T1 T2 T1
6∠34§
Systèmes monoprocesseur
• Pseudo-parallélisme : les systèmes monoprocesseur permettent
un parallélisme, où toutes les tâches s’exécutent sur le même processeur.
• Systèmes à traitement par lots
Processeur P1 Tâche T1 Tâche T2
• Systèmes à temps partagé
Processeur P1 T1 T2 T1 T2 T1 T2 T1
Systèmes monoprocesseur
• Pseudo-parallélisme : les systèmes monoprocesseur permettent
un parallélisme, où toutes les tâches s’exécutent sur le même processeur.
• Systèmes à traitement par lots
Processeur P1 Tâche T1 Tâche T2
• Systèmes à temps partagé
Processeur P1 T1 T2 T1 T2 T1 T2 T1
6∠34§
La programmation concurrente
Un paradigme de programmation qui tient compte, dans un programme, de l’existence de plusieurs unités d’exécution de base :
les processus et les threads.
La notion de processus
• Les processus sont considérés comme synonymes de programmes.
Ü un processus est un programme en cours d’exécution.
• Un processus possède un environnement d’exécution autonome : Ü chaque processus a son propre espace mémoire.
• Pour gérer la communication entre les processus, la plupart des OS utilisent les IPC (Inter Process Processing) : les pipes et les sockets. (
à étudier dans le cours suivant)
8∠34§
La notion de processus
• Les processus sont considérés comme synonymes de programmes.
Ü un processus est un programme en cours d’exécution.
• Un processus possède un environnement d’exécution autonome : Ü chaque processus a son propre espace mémoire.
• Pour gérer la communication entre les processus, la plupart des OS
utilisent les IPC (Inter Process Processing) : les pipes et les sockets.
(
à étudier dans le cours suivant)
La notion de processus
• Les processus sont considérés comme synonymes de programmes.
Ü un processus est un programme en cours d’exécution.
• Un processus possède un environnement d’exécution autonome : Ü chaque processus a son propre espace mémoire.
• Pour gérer la communication entre les processus, la plupart des OS utilisent les IPC (Inter Process Processing) : les pipes et les sockets.
(
à étudier dans le cours suivant)
8∠34§
La notion de thread
• Les threads sont aussi appelés processus légers
Ü la création d’un thread nécessite moins de ressources qu’un processus.
• Les threads sont créés par des processus. Les threads partagent
les ressources du processus, y compris la mémoire et les fichiers ouverts.
• Cela rend la communication efficace mais potentiellement problématique
(synchronisations et gestion des ressources partagées).
La notion de thread
• Les threads sont aussi appelés processus légers
Ü la création d’un thread nécessite moins de ressources qu’un processus.
• Les threads sont créés par des processus. Les threads partagent
les ressources du processus, y compris la mémoire et les fichiers ouverts.
• Cela rend la communication efficace mais potentiellement problématique (synchronisations et gestion des ressources partagées).
9∠34§
La notion de thread
• Les threads sont aussi appelés processus légers
Ü la création d’un thread nécessite moins de ressources qu’un processus.
• Les threads sont créés par des processus. Les threads partagent
les ressources du processus, y compris la mémoire et les fichiers ouverts.
• Cela rend la communication efficace mais potentiellement problématique
(synchronisations et gestion des ressources partagées).
Processus vs Thread
10∠34§
1 Systèmes multitâches
2 Les processus et les threads en Java 3 Quelques méthodes de la classe Thread
4 Gestion des ressources et des sections critiques
Les processus en Java
• La description du comportement d’un processus en Java se fait en implémentant la méthode main() dans une classe.
1 public class ProcessInstanciation {
2 public static void main(String[] args) { 3 System.out.println("Run with main method");
4 }
5 }
• La création d’un processus se fait en exécutant la méthode main().
Run with main method
12∠34§
Les processus en Java
• La description du comportement d’un processus en Java se fait en implémentant la méthode main() dans une classe.
1 public class ProcessInstanciation {
2 public static void main(String[] args) { 3 System.out.println("Run with main method");
4 }
5 }
• La création d’un processus se fait en exécutant la méthode main().
Run with main method
Les threads en Java
• La création d’un thread se fait de deux manières :
1
En dérivant la classe Thread et en implémentant la méthode run().
2
En dérivant de l’interface Runnable et en implémentant la méthode run().
• L’exécution d’un thread se fait en utilisant la méthode start(). Le code métier (développé dans la méthode run()) sera exécuté en tâche de fond.
13∠34§
Les threads en Java
• La création d’un thread se fait de deux manières :
1
En dérivant la classe Thread et en implémentant la méthode run().
2
En dérivant de l’interface Runnable et en implémentant la méthode run().
• L’exécution d’un thread se fait en utilisant la méthode start(). Le code
métier (développé dans la méthode run()) sera exécuté en tâche de fond.
Les threads en Java
• La création d’un thread se fait de deux manières :
1
En dérivant la classe Thread et en implémentant la méthode run().
2
En dérivant de l’interface Runnable et en implémentant la méthode run().
• L’exécution d’un thread se fait en utilisant la méthode start(). Le code métier (développé dans la méthode run()) sera exécuté en tâche de fond.
13∠34§
Les threads en Java
• La création d’un thread se fait de deux manières :
1
En dérivant la classe Thread et en implémentant la méthode run().
2
En dérivant de l’interface Runnable et en implémentant la méthode run().
• L’exécution d’un thread se fait en utilisant la méthode start(). Le code
métier (développé dans la méthode run()) sera exécuté en tâche de fond.
Méthode 1 : Etendre la classe Thread (1/2)
1 public class FromThreadClass extends Thread { 2 protected String name ;
3
4 public FromThreadClass(String id) { 5 this.name = id;
6 }
7
8 public void run() {
9 System.out.println("[Thread "+this.name+"] Run");
10 }
11 }
14∠34§
Méthode 1 : Etendre la classe Thread (2/2)
1 public class FromProcessClass {
2 public static void main(String[] args) {
3 FromThreadClass th1 = new FromThreadClass("TH1");
4 th1.start();
5 }
6 }
[Thread TH1] Run
Méthode 1 : Etendre la classe Thread (2/2)
1 public class FromProcessClass {
2 public static void main(String[] args) {
3 FromThreadClass th1 = new FromThreadClass("TH1");
4 th1.start();
5 }
6 }
[Thread TH1] Run
15∠34§
Méthode 2.1 : implémenter l’interface Runnable (1/2)
1 public class FromRunnableInterface implements Runnable { 2
3 public void run() {
4 System.out.println("[Thread] Run");
5 }
6 }
Méthode 2.1 : implémenter l’interface Runnable (2/2)
1 public class FromProcessClass {
2 public static void main(String[] args) {
3 Thread th1 = new Thread(new FromRunnableInterface());
4 th1.start();
5 }
6 }
[Thread] Run
17∠34§
Méthode 2.1 : implémenter l’interface Runnable (2/2)
1 public class FromProcessClass {
2 public static void main(String[] args) {
3 Thread th1 = new Thread(new FromRunnableInterface());
4 th1.start();
5 }
6 }
[Thread] Run
Méthode 2.2 : implémenter l’interface Runnable à chaud
1 public class FromProcessClass {
2 public static void main(String[] args) { 3 Thread th1 = new Thread(new Runnable(){
4 public void run() {
5 System.out.println("[Thread] Run");
6 }
7 });
8 th1.start();
9 }
10 }
[Thread] Run
18∠34§
Méthode 2.2 : implémenter l’interface Runnable à chaud
1 public class FromProcessClass {
2 public static void main(String[] args) { 3 Thread th1 = new Thread(new Runnable(){
4 public void run() {
5 System.out.println("[Thread] Run");
6 }
7 });
8 th1.start();
9 }
10 }
[Thread] Run
Cycle de vie d’un thread/processus
19∠34§
1 Systèmes multitâches
2 Les processus et les threads en Java 3 Quelques méthodes de la classe Thread
4 Gestion des ressources et des sections critiques
Les méthodes sleep() et join()
1 public class ThreadFils extends Thread { 2 protected String name ;
3
4 public ThreadFils(String name) { 5 this.name = name;
6 }
7
8 public void run() {
9 try {
10 System.out.println("[Thread "+this.name+"] Debut");
11 System.out.println("[Thread "+this.name+"] Sleep ...");
12 this.sleep(2000);
13 System.out.println("[Thread "+this.name+"] Fin");
14 } catch (InterruptedException e) { 15 e.printStackTrace();
16 }
17 }
18 }
21∠34§
Les méthodes sleep() et join()
1 public class Main {
2 public static void main(String[] args) {
3 try {
4 System.out.println("[Main Process] Debut");
5 ThreadFils f1 = new ThreadFils("f1");
6 f1.start();
7 f1.join();
8 System.out.println("[Main Process] Fin");
9 } catch (InterruptedException e) { 10 e.printStackTrace();
11 }
12 }
13 }
[Main Process] Debut [Thread f1] Debut [Thread f1] Sleep ... [Thread f1] Fin [Main Process] Fin
Les méthodes sleep() et join()
1 public class Main {
2 public static void main(String[] args) {
3 try {
4 System.out.println("[Main Process] Debut");
5 ThreadFils f1 = new ThreadFils("f1");
6 f1.start();
7 f1.join();
8 System.out.println("[Main Process] Fin");
9 } catch (InterruptedException e) { 10 e.printStackTrace();
11 }
12 }
13 }
[Main Process] Debut [Thread f1] Debut [Thread f1] Sleep ...
[Thread f1] Fin [Main Process] Fin
22∠34§
Les méthodes sleep() et join()
1 public class Main {
2 public static void main(String[] args) {
3 try {
4 System.out.println("[Main Process] Debut");
5 ThreadFils f1 = new ThreadFils("f1");
6 f1.start();
7 f1.join(1000);
8 System.out.println("[Main Process] Fin");
9 } catch (InterruptedException e) { 10 e.printStackTrace();
11 }
12 }
13 }
[Main Process] Debut [Thread f1] Debut [Thread f1] Sleep ... [Main Process] Fin [Thread f1] Fin
Les méthodes sleep() et join()
1 public class Main {
2 public static void main(String[] args) {
3 try {
4 System.out.println("[Main Process] Debut");
5 ThreadFils f1 = new ThreadFils("f1");
6 f1.start();
7 f1.join(1000);
8 System.out.println("[Main Process] Fin");
9 } catch (InterruptedException e) { 10 e.printStackTrace();
11 }
12 }
13 }
[Main Process] Debut [Thread f1] Debut [Thread f1] Sleep ...
[Main Process] Fin [Thread f1] Fin
23∠34§
La méthode interrupt()
1 public class Main {
2 public static void main(String[] args) {
3 try {
4 System.out.println("[Main Process] Debut");
5 ThreadFils f1 = new ThreadFils("f1");
6 f1.start();
7 f1.join(1000);
8 f1.interrupt();
9 System.out.println("[Main Process] Fin");
10 } catch (InterruptedException e) {e.printStackTrace();}
11 }
12 }
[Thread f1] Debut [Thread f1] Sleep ... [Main Process] Fin
java.lang.InterruptedException: sleep interrupted at java.lang.Thread.sleep(Native Method) at ThreadFils.run(ThreadFils.java:15)
La méthode interrupt()
1 public class Main {
2 public static void main(String[] args) {
3 try {
4 System.out.println("[Main Process] Debut");
5 ThreadFils f1 = new ThreadFils("f1");
6 f1.start();
7 f1.join(1000);
8 f1.interrupt();
9 System.out.println("[Main Process] Fin");
10 } catch (InterruptedException e) {e.printStackTrace();}
11 }
12 }
[Thread f1] Debut [Thread f1] Sleep ...
[Main Process] Fin
java.lang.InterruptedException: sleep interrupted at java.lang.Thread.sleep(Native Method) at ThreadFils.run(ThreadFils.java:15)
24∠34§
1 Systèmes multitâches
2 Les processus et les threads en Java 3 Quelques méthodes de la classe Thread
4 Gestion des ressources et des sections critiques
Quelques définitions
• Les threads partagent le même espace mémoire, ils accèdent aux mêmes ressources (les ressources critiques ou les ressources partagées ).
• Les sections critiques sont les instructions que plusieurs threads sont susceptibles d’exécuter au même moment et où les ressources partagées sont mis à jours.
• En Java, il existe plusieurs stratégies pour s’assurer qu’une section de code est exécuté par un seul thread.
26∠34§
Quelques définitions
• Les threads partagent le même espace mémoire, ils accèdent aux mêmes ressources (les ressources critiques ou les ressources partagées ).
• Les sections critiques sont les instructions que plusieurs threads sont susceptibles d’exécuter au même moment et où les ressources partagées sont mis à jours.
• En Java, il existe plusieurs stratégies pour s’assurer qu’une section de code
est exécuté par un seul thread.
Quelques définitions
• Les threads partagent le même espace mémoire, ils accèdent aux mêmes ressources (les ressources critiques ou les ressources partagées ).
• Les sections critiques sont les instructions que plusieurs threads sont susceptibles d’exécuter au même moment et où les ressources partagées sont mis à jours.
• En Java, il existe plusieurs stratégies pour s’assurer qu’une section de code est exécuté par un seul thread.
26∠34§
Quelques définitions
• Les threads partagent le même espace mémoire, ils accèdent aux mêmes ressources (les ressources critiques ou les ressources partagées ).
• Les sections critiques sont les instructions que plusieurs threads sont susceptibles d’exécuter au même moment et où les ressources partagées sont mis à jours.
• En Java, il existe plusieurs stratégies pour s’assurer qu’une section de code
est exécuté par un seul thread.
Problèmes de synchronisation
1 public class Ressource { 2 private int cpt ; 3
4 public Ressource() { 5 this.cpt = 0;
6 }
7
8 public int getCpt() {
9 return cpt;
10 }
11
12 public void updateCpt() { 13 this.cpt = this.cpt +1;
14 }
15 }
27∠34§
Problèmes de synchronisation
1 public class ThreadFils extends Thread { 2 private Ressource r ;
3
4 public ThreadFils(Ressource r){
5 this.r = r ;
6 }
7
8 public void run() {
9 for(int i=0;i<100;i++){
10 try {
11 Thread.sleep(100);
12 this.r.updateCpt();
13 }
14 catch (InterruptedException e){
15 e.printStackTrace();
16 }
17 }
18 }
19 }
Problèmes de synchronisation
1 public class Process {
2 public static void main(String[] args) 3 throws InterruptedException {
4 Ressource r = new Ressource();
5 ThreadFils f1 = new ThreadFils(r);
6 ThreadFils f2 = new ThreadFils(r);
7 f1.start();
8 f2.start();
9 f1.join();
10 f2.join();
11 System.out.println(r.getCpt());
12 }
13 }
137
29∠34§
Problèmes de synchronisation
1 public class Process {
2 public static void main(String[] args) 3 throws InterruptedException {
4 Ressource r = new Ressource();
5 ThreadFils f1 = new ThreadFils(r);
6 ThreadFils f2 = new ThreadFils(r);
7 f1.start();
8 f2.start();
9 f1.join();
10 f2.join();
11 System.out.println(r.getCpt());
12 }
13 }
137
Comment expliquer ce calcul incorrect ?
1 //this.value = this.value + 1; 2 lda value
3 add #1 4 sta value
1 //this.value = this.value + 1; 2 lda value
3 add #1 4 sta value
value=1000 value=1000
value=1001 value=1001
Après une itération ?
value=1001
30∠34§
Comment expliquer ce calcul incorrect ?
1 //this.value = this.value + 1;
2 lda value 3 add #1 4 sta value
1 //this.value = this.value + 1;
2 lda value 3 add #1 4 sta value
value=1000 value=1000
value=1001 value=1001
Après une itération ?
value=1001
Comment expliquer ce calcul incorrect ?
1 //this.value = this.value + 1;
2 lda value 3 add #1 4 sta value
1 //this.value = this.value + 1;
2 lda value 3 add #1 4 sta value
value=1000
value=1000
value=1001 value=1001
Après une itération ?
value=1001
30∠34§
Comment expliquer ce calcul incorrect ?
1 //this.value = this.value + 1;
2 lda value 3 add #1 4 sta value
1 //this.value = this.value + 1;
2 lda value 3 add #1 4 sta value
value=1000 value=1000
value=1001 value=1001
Après une itération ?
value=1001
Comment expliquer ce calcul incorrect ?
1 //this.value = this.value + 1;
2 lda value 3 add #1 4 sta value
1 //this.value = this.value + 1;
2 lda value 3 add #1 4 sta value
value=1000 value=1000
value=1001
value=1001
Après une itération ?
value=1001
30∠34§
Comment expliquer ce calcul incorrect ?
1 //this.value = this.value + 1;
2 lda value 3 add #1 4 sta value
1 //this.value = this.value + 1;
2 lda value 3 add #1 4 sta value
value=1000 value=1000
value=1001 value=1001
Après une itération ?
value=1001
Comment expliquer ce calcul incorrect ?
1 //this.value = this.value + 1;
2 lda value 3 add #1 4 sta value
1 //this.value = this.value + 1;
2 lda value 3 add #1 4 sta value
value=1000 value=1000
value=1001 value=1001
Après une itération ?
value=1001
30∠34§
Les méthodes synchronisées (les moniteurs)
1 public class Ressource { 2 private int cpt ; 3
4 public Ressource() { 5 this.cpt = 0;
6 }
7
8 public synchronized int getCpt() {
9 return cpt;
10 }
11
12 public synchronized void updateCpt() { 13 this.cpt = this.cpt +1;
14 }
15 }
Les Locks
1 public class Ressource { 2 private int cpt ;
3 private ReentrantLock myLock = new ReentrantLock();
4
5 public Ressource() { 6 this.cpt = 0;
7 }
8
9 public int getCpt() { 10 this.myLock.lock();
11 int copy = this.cpt;
12 this.myLock.unlock();
13 return copy;
14 }
15
16 public void updateCpt() { 17 this.myLock.lock();
18 this.cpt = this.cpt +1;
19 this.myLock.unlock();
20 }
21 }
32∠34§
Les sémaphores
1 public class Ressource { 2 private int cpt ;
3 private Semaphore sem = new Semaphore(1);
4
5 public Ressource() { 6 this.cpt = 0;
7 }
8
9 public int getCpt() throws InterruptedException { 10 this.sem.acquire();
11 int copy = this.cpt;
12 this.sem.release();
13 return copy;
14 }
15
16 public void updateCpt() throws InterruptedException { 17 this.sem.acquire();
18 this.cpt = this.cpt +1;
19 this.sem.release();
20 }
21 }