{"id":63,"date":"2017-09-09T15:36:30","date_gmt":"2017-09-09T15:36:30","guid":{"rendered":"https:\/\/wp-systeme.lip6.fr\/potop-butucaru\/?p=63"},"modified":"2023-04-03T16:12:43","modified_gmt":"2023-04-03T16:12:43","slug":"programmation-concurrente","status":"publish","type":"post","link":"https:\/\/wp-systeme.lip6.fr\/potop-butucaru\/2017\/09\/09\/programmation-concurrente\/","title":{"rendered":"Programmation Concurrente"},"content":{"rendered":"<section>\n<section class=\"toc-pause\">\n<h1>Introduction<\/h1>\n<\/section>\n<section>Dans une ex\u00e9cution s\u00e9quentielle, une grande partie du temps est pass\u00e9e \u00e0 attendre.<small>Exemple: lors de l&#8217;attente de r\u00e9ception d&#8217;un message dans un socket, lors de la lecture d&#8217;un fichier, &#8230;<\/small><\/p>\n<\/section>\n<section>\n<div>\n<p>Lecture de deux sockets :<\/p>\n<pre><code class=\"java\" data-trim=\"\">\r\nSocket s1 = new Socket(host, port);\r\nSocket s2 = new Socket(host2, port2);\r\nInputStream in1 = s1.getInputStream();\r\nInputStream in2 = s2.getInputStream();\r\nOutputStream out = s2.getOutputStream();\r\n\r\nint a = in1.read();\r\nint b = in2.read();\r\nint c = a+b;\r\nout.write(c);\r\n                        <\/code><\/pre>\n<\/div>\n<p><object class=\"fragment\" data=\"https:\/\/pagesperso.lip6.fr\/Maria.Gradinariu\/sites\/Maria.Gradinariu\/IMG\/html\/c8-figures\/example1-sync.svg\" type=\"image\/svg+xml\" width=\"300\" height=\"150\" data-mce-fragment=\"1\"><\/object><\/section>\n<section>C&#8217;est pourquoi, il est souvent utile (et m\u00eame parfois m\u00eame n\u00e9cessaire) d&#8217;ex\u00e9cuter des actions en parall\u00e8le.<\/section>\n<section>\n<h2>Exemple de l&#8217;architecture client-serveur<\/h2>\n<p>Dans une architecture client\/serveur, deux clients qui veulent communiquer ensemble, doivent passer par un serveur.<\/p>\n<p><object id=\"alphasvg\" class=\"fragment\" data=\"https:\/\/pagesperso.lip6.fr\/Maria.Gradinariu\/sites\/Maria.Gradinariu\/IMG\/html\/c8-figures\/client-serveur.svg\" type=\"image\/svg+xml\" width=\"300\" height=\"150\" data-mce-fragment=\"1\"><\/object><\/section>\n<section>\n<h2>Exemple de l&#8217;architecture client-serveur<\/h2>\n<pre class=\"fragment hide-with-next-fragment\"><code class=\"java\" data-trim=\"\">\r\n\r\nServerSocket serveur = new ServerSocket(8080);\r\nSocket alice = server.accept();\r\nSocket bob = server.accept();\r\n\r\nScanner       aliceIn  = new Scanner(alice.getInputStream());\r\nScanner       bobIn    = new Scanner(bob.getInputStream());\r\n\r\nPrinterWriter aliceOut = new PrinterWriter(\r\n                            alice.getOutputStream(), true);\r\nPrinterWriter bobOut   = new PrinterWriter(\r\n                            bob.getOutputStream(), true);\r\n\r\n\/\/ ....\r\n                        <\/code><\/pre>\n<pre class=\"fragment hide-with-next-fragment\"><code class=\"java\" data-trim=\"\">\r\n\r\nServerSocket serveur = new ServerSocket(8080);\r\nSocket alice = server.accept();\r\nSocket bob = server.accept();\r\n\r\n\/\/ ....\r\n\r\nString message = aliceIn.readLine();\r\nbobOut.println(message);\r\n\r\nmessage = bobIn.readLine();\r\naliceOut.println(message);\r\n                        <\/code><\/pre>\n<\/section>\n<section>\n<pre><code class=\"java\" data-trim=\"\">\r\n\r\nString message = aliceIn.readLine();\r\nbobOut.println(message);\r\nmessage = bobIn.readLine();\r\naliceOut.println(message);\r\n\r\n                        <\/code><\/pre>\n<p><object data=\"https:\/\/pagesperso.lip6.fr\/Maria.Gradinariu\/sites\/Maria.Gradinariu\/IMG\/html\/c8-figures\/client-serveur2.svg\" type=\"image\/svg+xml\" width=\"300\" height=\"150\" data-mce-fragment=\"1\"><\/object><\/section>\n<section>\n<h2>Serveur multithread\u00e9<\/h2>\n<p><object data=\"https:\/\/pagesperso.lip6.fr\/Maria.Gradinariu\/sites\/Maria.Gradinariu\/IMG\/html\/c8-figures\/client-serveur-async.svg\" type=\"image\/svg+xml\" width=\"300\" height=\"150\" data-mce-fragment=\"1\"><\/object><\/section>\n<section>\n<h2>Calculs intensifs<\/h2>\n<p>En plus de la n\u00e9cessit\u00e9 d&#8217;utiliser les threads pour pouvoir faire plusieurs choses en m\u00eame temps. Il est parfois utile de pouvoir parall\u00e9liser un calcul pour utiliser plus efficacement les mutliple coeurs du CPU (pour effectuer un calcul plus vite).<\/p>\n<p class=\"fragment\">Dans ce context le probl\u00e8me est parfois plus compliqu\u00e9 car des threads travaillant sur des donn\u00e9es communes doivent faire attention lorsqu&#8217;ils acc\u00e8dent de mani\u00e8re <b>concurrente<\/b>au m\u00eame donn\u00e9es.<\/p>\n<\/section>\n<\/section>\n<section>\n<section class=\"toc-pause\">\n<h1>Les processus et les threads<\/h1>\n<\/section>\n<section>\n<h2>Diff\u00e9rences entre processus et threads<\/h2>\n<p class=\"fragment\"><b>Un processus<\/b> est un programme qui s&#8217;ex\u00e9cute. Il poss\u00e8de son propre espace m\u00e9moire.<\/p>\n<p class=\"fragment\"><b>Un thread<\/b> est un ensemble d&#8217;instructions qui s&#8217;ex\u00e9cutent (un sous-ensemble des instructions du processus en cours). <span class=\"fragment\">Il utilise le m\u00eame espace m\u00e9moire et les m\u00eames resources que le processus dans lequel il s&#8217;ex\u00e9cute. <\/span><span class=\"fragment\">Cependant, il peut s&#8217;ex\u00e9cuter de mani\u00e8re ind\u00e9pendantes de (parfois en m\u00eame temps que) son processus (possiblement sur un coeur diff\u00e9rent du CPU ).<\/span><\/p>\n<\/section>\n<section>\n<h2>Le processus principal<\/h2>\n<p>La class <code>Runtime<\/code> d\u00e9finie un objet qui repr\u00e9sente un environement d&#8217;ex\u00e9cution. On obtient l&#8217;environement de l&#8217;application courante \u00e0 l&#8217;aide de la m\u00e9thode statique <code>Runtime.getRuntime()<\/code><\/p>\n<pre><code class=\"java\" data-trim=\"\">\r\nRuntime monApplication = Runtime.getRuntime();\r\n                      <\/code><\/pre>\n<\/section>\n<section>\n<h2>Cr\u00e9ation de processus<\/h2>\n<p>A partir d&#8217;un objet <code>Runtime<\/code> on peut cr\u00e9er des processus (objects de type <code>Process<\/code>) avec la m\u00e9thode <code>exec<\/code>. <span class=\"fragment\">Ou bien en utilisant la classe <code>ProcessBuilder<\/code>.<\/span><\/p>\n<pre><code class=\"java\" data-trim=\"\">\r\n\r\nRuntime monApplication = Runtime.getRuntime();\r\n\r\nProcess p1 = monApplication.exec(\"cat index.html\");\r\nProcess p2 = monApplication.exec(\"python\", \"script.py\");\r\n\r\nProcessBuilder pb = new ProcessBuilder(\"espeak\", \"hello, how are you?\");\r\nProcess p3 = pb.start();\r\npb = new ProcessBuilder(\"say\", \"Bonjour tout le monde!\");\r\nProcess p4 = pb.start();\r\n\r\n\/\/ Waits for the command to finish.\r\np1.waitFor();\r\np2.waitFor();\r\np3.waitFor();\r\np4.waitFor();\r\n\r\n                        <\/code><\/pre>\n<\/section>\n<section>\n<h2>Communication avec un processus<\/h2>\n<p>Les m\u00e9thodes <code>getOutputStream()<\/code>, <code>getInputStream()<\/code>, et <code>getErrorStream()<\/code> permettent de communiquer avec le processus.<\/p>\n<pre><code class=\"java\" data-trim=\"\">\r\n\r\nProcess p2 = monApplication.exec(\"python script.py\");\r\nBufferedReader in = new BufferedReader(new InputStreamReader(p.getErrorStream()));\r\nString line;\r\nwhile ((line = in.readLine()) != null) {\r\n      System.out.println(line);\r\n}\r\n                            <\/code><\/pre>\n<pre><code class=\"java\" data-trim=\"\">\r\n\/usr\/local\/bin\/python: can't open file 'script.py': [Errno 2] No such file or directory\r\n                            <\/code><\/pre>\n<\/section>\n<section>\n<h2>Avantage des Threads<\/h2>\n<p>Dans un processus Java, on peut cr\u00e9er plusieurs fils d&#8217;ex\u00e9cution (threads) internes<\/p>\n<ul>\n<li class=\"fragment\">un seul processus (au sens syst\u00e8me d&#8217;expl)<\/li>\n<li class=\"fragment\">possibilit\u00e9s de contr\u00f4le plus fin (priorit\u00e9, interruption&#8230;)<\/li>\n<li class=\"fragment\">c&#8217;est la JVM qui assure l&#8217;ordonnancement (concurrence)<\/li>\n<li class=\"fragment\">espace m\u00e9moire commun entre les diff\u00e9rents threads<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<\/section>\n<section>\n<h2>Cr\u00e9er un Thread<\/h2>\n<p>Java propose la classe <code>Thread<\/code>. <span class=\"fragment\" data-fragment-index=\"0\">Lorsqu&#8217;un objet <code>Thread<\/code> est d\u00e9marr\u00e9 avec la m\u00e9thode <code>start()<\/code>, le code contenu dans la m\u00e9thode <code>run()<\/code> est \u00e9x\u00e9cut\u00e9 de mani\u00e8re ind\u00e9pendante.<\/span><\/p>\n<p class=\"fragment\" data-fragment-index=\"1\">Il y a deux possibilit\u00e9s pour cr\u00e9er son propre thread :<\/p>\n<ul>\n<li class=\"fragment\" data-fragment-index=\"2\"><i class=\"fa fa-thumbs-o-down\" aria-hidden=\"true\"><\/i>On peut cr\u00e9er une sous-classe de <code>Thread<\/code> et red\u00e9finir la m\u00e9thode <code>run()<\/code><\/li>\n<li class=\"fragment\" data-fragment-index=\"3\"><i class=\"fa fa-thumbs-o-up\" aria-hidden=\"true\"><\/i>On peut cr\u00e9er une classe qui impl\u00e9mente l&#8217;interface fonctionelle <code>Runnable<\/code> et cr\u00e9er un <code>Thread<\/code> en donnant une instance de notre classe en param\u00e8tre du constructeur<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<\/section>\n<section>\n<h3>Cr\u00e9er une classe qui impl\u00e9mente <code>Runnable<\/code><\/h3>\n<pre><code class=\"java\" data-trim=\"\">\r\nclass TacheDeFond implements Runnable {\r\n  @Override\r\n  public void run() {\r\n    int i = 40;\r\n    while(i--&gt;0) {\r\n      System.out.println(i);\r\n    }\r\n  }\r\n}\r\n                      <\/code><\/pre>\n<pre class=\"fragment\"><code class=\"java\" data-trim=\"\">\r\nRunnable t = new TacheDeFond();\r\nnew Thread(t).start();\r\nSystem.out.println(\"Le thread a \u00e9t\u00e9 lanc\u00e9\");\r\n                      <\/code><\/pre>\n<pre class=\"fragment\"><code class=\"java\" data-trim=\"\">\r\nRunnable t = new TacheDeFond();\r\nnew Thread(t).start();\r\nnew Thread(t).start();\r\nSystem.out.println(\"Les threads ont \u00e9t\u00e9 lanc\u00e9s\");\r\n                      <\/code><\/pre>\n<\/section>\n<section>\n<h3>Cr\u00e9er une classe anonyme qui impl\u00e9mente <code>Runnable<\/code><\/h3>\n<pre><code class=\"java\" data-trim=\"\">\r\nRunnable t = new Runnable() {\r\n\r\n    @Override\r\n    public void run() {\r\n      int i = 40;\r\n      while(i--&gt;0) {\r\n        System.out.println(i);\r\n      }\r\n    }\r\n\r\n}; \/\/ la classe est d\u00e9finie en m\u00eame temps que son instanciation\r\n\r\nnew Thread(t).start();\r\nnew Thread(t).start();\r\nSystem.out.println(\"Les threads ont \u00e9t\u00e9 lanc\u00e9s\");\r\n                      <\/code><\/pre>\n<\/section>\n<section>\n<h3>Cr\u00e9er un lambda <code>Runnable<\/code> (java 8) <i class=\"fa fa-thumbs-o-up\" aria-hidden=\"true\"><\/i><\/h3>\n<pre><code class=\"java\" data-trim=\"\">\r\nRunnable t = () -&gt; {\r\n      int i = 40;\r\n      while(i--&gt;0) {\r\n        System.out.println(i);\r\n      }\r\n    };\r\n\r\nnew Thread(t).start();\r\nnew Thread(t).start();\r\nSystem.out.println(\"Les threads ont \u00e9t\u00e9 lanc\u00e9s\");\r\n                      <\/code><\/pre>\n<\/section>\n<section>\n<h3>Cr\u00e9er une classe qui impl\u00e9mente <code>Runnable<\/code><\/h3>\n<pre><code class=\"java\" data-trim=\"\">\r\nclass TacheDeFond implements Runnable {\r\n  private int iter;\r\n\r\n  TacheDeFond(int iter) {\r\n    this.iter = iter;\r\n  }\r\n\r\n  @Override\r\n  public void run() {\r\n    while(iter--&gt;0) {\r\n      System.out.println(iter);\r\n    }\r\n  }\r\n}\r\n                      <\/code><\/pre>\n<p class=\"fragment\"><i class=\"fa fa-exclamation-triangle\" aria-hidden=\"true\"><\/i><small>ici les deux threads utilisent le m\u00eame objet <code>Runnable<\/code> donc le m\u00eame attribut <code>iter<\/code><\/small><\/p>\n<pre><code class=\"java\" data-trim=\"\">\r\nRunnable t = new TacheDeFond(50);\r\nnew Thread(t).start();\r\nnew Thread(t).start();\r\nSystem.out.println(\"Les threads ont \u00e9t\u00e9 lanc\u00e9s\");\r\n                      <\/code><\/pre>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<\/section>\n<section>\n<h3>Cr\u00e9er une classe qui impl\u00e9mente <code>Runnable<\/code><\/h3>\n<pre><code class=\"java\" data-trim=\"\">\r\nclass TacheDeFond implements Runnable {\r\n  private int iter;\r\n\r\n  TacheDeFond(int iter) {\r\n    this.iter = iter;\r\n  }\r\n\r\n  @Override\r\n  public void run() {\r\n    while(iter--&gt;0) {\r\n      System.out.println(iter);\r\n    }\r\n  }\r\n}\r\n                      <\/code><\/pre>\n<p class=\"fragment\">\n<pre><code class=\"java\" data-trim=\"\">\r\nRunnable t = new TacheDeFond(50);\r\nnew Thread(t).start();\r\nt = new TacheDeFond(50);\r\nnew Thread(t).start();\r\nSystem.out.println(\"Les threads ont \u00e9t\u00e9 lanc\u00e9s\");\r\n                    <\/code><\/pre>\n<p>&nbsp;<\/p>\n<\/section>\n<\/section>\n<section>\n<section class=\"toc-pause\">\n<h1>Gestion des Threads<\/h1>\n<\/section>\n<section>\n<h2>Propri\u00e9t\u00e9 d&#8217;un thread<\/h2>\n<p>Chaque thread poss\u00e8de :<\/p>\n<ul>\n<li class=\"fragment\">un nom : <code>[get\/set]Name()<\/code><\/li>\n<li class=\"fragment\">une priorit\u00e9 : <code>[get\/set]Priority()<\/code><\/li>\n<li class=\"fragment\">un statut daemon : <code>[is\/set]Daemon()<\/code><\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<p class=\"fragment\">La Machine Virtuelle Java continue de tourner jusqu&#8217;\u00e0 ce que:<\/p>\n<ul>\n<li class=\"fragment\">soit la m\u00e9thode <code>exit()<\/code> de la classe <code>Runtime<\/code> soit appel\u00e9e<\/li>\n<li class=\"fragment\">soit tous les threads non marqu\u00e9s &#8220;daemon&#8221; soient termin\u00e9s. <span class=\"fragment\">On peut savoir si un thread est termin\u00e9 via la m\u00e9thode <code>isAlive()<\/code><\/span><\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<\/section>\n<section>\n<h2>Le thread courant<\/h2>\n<p>On peut r\u00e9cuperer l&#8217;instance du thead courant \u00e0 l&#8217;aide de la m\u00e9thode statique <code>Thread.currentThread()<\/code>.<\/p>\n<pre><code class=\"java\" data-trim=\"\">\r\n\r\nnew Thread(() -&gt; {\r\n  int i = 20;\r\n  while(i--&gt;0) {\r\n    System.out.println(Thread.currentThread().getName()+\" : \"+i);\r\n  }\r\n}, \"mon super thread\").start();\r\n\r\nSystem.out.println(Thread.currentThread().getName()+\" : le thread a \u00e9t\u00e9 lanc\u00e9\");\r\n\r\n                    <\/code><\/pre>\n<p><a href=\"https:\/\/repl.it\/EDYS\" target=\"_blank\" rel=\"noopener\"><i class=\"fa fa-play\" aria-hidden=\"true\"><\/i>run it!<\/a><\/section>\n<section>\n<h2>Gestion d&#8217;un thread<\/h2>\n<p>Un thread est lanc\u00e9 avec la m\u00e9thode <code>start()<\/code>. Le code de la m\u00e9thode <code>run()<\/code> est alors ex\u00e9cut\u00e9. <b>Un thread ne peut pas \u00eatre int\u00e9rrompu lorsqu&#8217;il effectue des calculs<\/b>.<\/p>\n<pre class=\"fragment hide-with-next-fragment\"><code class=\"java\" data-trim=\"\">\r\nprivate static void longComputation() {\r\n  long timeToWait = 1000 + System.currentTimeMillis();\r\n  while(System.currentTimeMillis() &lt; timeToWait);\r\n}\r\n                    <\/code><\/pre>\n<pre class=\"fragment\"><code class=\"java\" data-trim=\"\">\r\nThread t1 = new Thread(() -&gt; {\r\n  int i = 10;\r\n  while(i--&gt;0) {\r\n    System.out.println(\"t1: \"+i);\r\n    longComputation();\r\n  }\r\n});\r\nt1.start();\r\nThread.sleep(5000);\r\nSystem.out.println(\"trying to stop the thread\");\r\nt1.interrupt();\r\n                    <\/code><\/pre>\n<p class=\"fragment\">ici, le thread n&#8217;est pas interrompu au milieu.<\/p>\n<\/section>\n<section>\n<h2>Interrumption d&#8217;un tread<\/h2>\n<p>Un thread peut v\u00e9rifier si un autre thread tente de l&#8217;interrompre \u00e0 l&#8217;aide des m\u00e9thodes <code>interrupted()<\/code> ou <code>isInterruped()<\/code>.<\/p>\n<pre><code class=\"java\" data-trim=\"\">\r\n\r\nThread t2 = new Thread(() -&gt; {\r\n  int i = 10;\r\n  while(i--&gt;0 &amp;&amp; !Thread.currentThread().interrupted()) {\r\n    System.out.println(\"t2: \"+i);\r\n    longComputation();\r\n  }\r\n});\r\nt2.start();\r\nThread.sleep(5000);\r\nt2.interrupt();\r\nSystem.out.println(\"trying to stop the thread\");\r\n\r\n                      <\/code><\/pre>\n<p>Diff\u00e9rence entre <code>interrupted()<\/code> et <code>isInterruped()<\/code> ? <span class=\"fragment\">Le status &#8220;interrompu&#8221; d&#8217;un thread est r\u00e9initiais\u00e9 \u00e0 <code>false<\/code> apr\u00e8s un appelle \u00e0 <code>interrupted()<\/code>.<\/span><\/p>\n<\/section>\n<section>\n<h2>Interruption d&#8217;un thread<\/h2>\n<p>Un thread peut aussi \u00eatre interrompu lorsqu&#8217;il est en attente de quelque chose. Par exemple avec la m\u00e9thode <code>sleep(long milliseconds)<\/code> (elle lance une exception <code>InterruptedException<\/code>).<\/p>\n<pre><code class=\"java\" data-trim=\"\">\r\n\r\nThread t2 = new Thread(() -&gt; {\r\n    int i = 10;\r\n    try {\r\n      while(i--&gt;0) {\r\n        System.out.println(\"t2: \"+i);\r\n        longComputation();\r\n        Thread.sleep(1000);\r\n      }\r\n    } catch(Exception e) { System.out.println(e); }\r\n  });\r\nt2.start();\r\nThread.sleep(5000);\r\nt2.interrupt();\r\nSystem.out.println(\"trying to stop the thread\");\r\n\r\n<\/code><\/pre>\n<p><a href=\"https:\/\/repl.it\/ED9P\" target=\"_blank\" rel=\"noopener\"><i class=\"fa fa-play\" aria-hidden=\"true\"><\/i>run it!<\/a><\/section>\n<section>\n<h2>Attendre la fin d&#8217;un autre thread<\/h2>\n<p>Le m\u00e9thode <b>bloquante<\/b> <code>join()<\/code> permet d&#8217;attendre un thread. <span class=\"fragment\">Comme elle &#8220;attend&#8221;, on peut \u00eatre interrompu dans cette attente (elle lance une exception <code>InterruptedException<\/code>)<\/span><\/p>\n<pre class=\"fragment\"><code class=\"java\" data-trim=\"\">\r\n\r\nThread t1 = new Thread(() -&gt; {\r\n  longComputation();\r\n  longComputation();\r\n});\r\nThread t2 = new Thread(() -&gt; {\r\n  try {\r\n    longComputation();\r\n    t1.join();\r\n    longComputation();\r\n  } catch(Exception e) { }\r\n});\r\nt1.start();\r\nt2.start();\r\nt1.join();\r\nt2.join();\r\nSystem.out.println(\"Les threads ont termin\u00e9\");\r\n                    <\/code><\/pre>\n<p><a class=\"fragment\" href=\"https:\/\/repl.it\/EDob\" target=\"_blank\" rel=\"noopener\"><i class=\"fa fa-play\" aria-hidden=\"true\"><\/i>run it!<\/a><\/section>\n<section>\n<h2>Execution des Threads<\/h2>\n<p>Dans les exemples pr\u00e9c\u00e9dents, on a vu comment cr\u00e9er des threads &#8220;\u00e0 la main&#8221; \u00e0 partir d&#8217;un code qu&#8217;on voulait ex\u00e9cuter (le Runnable). <span class=\"fragment\">C&#8217;est utile lorsque l&#8217;on a une application <b>qui doit absolument faire certaines choses sur des threads diff\u00e9rents.<\/b><\/span><\/p>\n<p class=\"fragment\">Cependant, on veut souvent uniquement ex\u00e9cuter <b>des t\u00e2ches sans se soucier r\u00e9ellement de la mani\u00e8re dont elle sont ex\u00e9cut\u00e9es<\/b>. Dans ce cas on va utiliser l&#8217;outil <code>Executor<\/code>.<\/p>\n<\/section>\n<section>\n<h2>Execution des Threads<\/h2>\n<p>Un <code>Executor<\/code> doit \u00eatre utilis\u00e9 lorsque l&#8217;on veut ex\u00e9cuter des t\u00e2ches (potentiellement gourmandes), de mani\u00e8re efficace (r\u00e9parties plusieurs coeurs du CPU), de mani\u00e8re asynchrone (\u00eatre averti lorsqu&#8217;elles sont termin\u00e9es).<\/p>\n<p>Ex: <span class=\"fragment\">charger des textures dans un jeu vid\u00e9o<\/span><span class=\"fragment\">, appliquer des filtres dans un logiciel de retouche photo<\/span><span class=\"fragment\">, recevoir des donn\u00e9es d&#8217;un client et y repondre.<\/span><\/p>\n<\/section>\n<section>\n<h2>Execution des Threads<\/h2>\n<p>Avantages d&#8217;un Executor :<\/p>\n<ul>\n<li class=\"fragment\">la mani\u00e8re dont les t\u00e2ches s&#8217;ex\u00e9cutent est abstraite<\/li>\n<li class=\"fragment\">la JVM peut optimiser l&#8217;utilisation des threads servant \u00e0 ex\u00e9cuter ces t\u00e2ches<\/li>\n<li class=\"fragment\">on ne cr\u00e9e pas un Thread par t\u00e2che (la cr\u00e9ation d&#8217;un Thread est couteuse)<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<\/section>\n<section>\n<h3><code>Executor<\/code> et <code>ExecutorService<\/code><\/h3>\n<p><code>Executor<\/code> est une interface d\u00e9finissant la capacit\u00e9 d&#8217;un objet \u00e0 ex\u00e9cuter des t\u00e2ches <code>Runnable<\/code>. <span class=\"fragment\">L&#8217;interface <code>ExecutorService<\/code> d\u00e9finit en plus la capacit\u00e9 \u00e0 ex\u00e9cuter des <code>Callable<\/code> et ajoute des m\u00e9thodes pour g\u00e9rer l&#8217;avancement des t\u00e2ches.<\/span><\/p>\n<p class=\"fragment\">On peut cr\u00e9er un objet de type <code>ThreadPoolExecutor<\/code> (qui impl\u00e9mente <code>ExecutorService<\/code>) avec la m\u00e9thode statique <code>Executors.newFixedThreadPool(int nThreads)<\/code>. <span class=\"fragment\">L&#8217;ex\u00e9cution des t\u00e2ches se fait alors sur un ensemble fini de threads.<\/span><\/p>\n<\/section>\n<section>\n<h3>Utilisation de <code>Executor<\/code><\/h3>\n<pre><code class=\"java\" data-trim=\"\">\r\nExecutorService pool = Executors.newFixedThreadPool(2);\r\npool.submit(fonctionCompliquee1);\r\npool.submit(fonctionCompliquee2);\r\npool.submit(fonctionCompliquee3);\r\ntry {\r\n    System.out.println(\"attempt to shutdown executor\");\r\n    pool.shutdown();\r\n    pool.awaitTermination(5, TimeUnit.SECONDS);\r\n}\r\ncatch (InterruptedException e) {\r\n    System.err.println(\"tasks interrupted\");\r\n}\r\n                    <\/code><\/pre>\n<\/section>\n<section>\n<h2>fonctions <code>Callable<\/code><\/h2>\n<p>lorsque les fonctions que l&#8217;on souhaite ex\u00e9cut\u00e9es retournent une valeur alors ce sont des <code>Callable&lt;V&gt;<\/code> (interface fonctionnelle contenant une seule m\u00e9thode <code>V call()<\/code>)<\/p>\n<pre><code class=\"java\" data-trim=\"\">\r\nExecutorService pool = Executors.newFixedThreadPool(2);\r\npool.submit(() -&gt; { return racineCarrePrecise(2,10000); } );\r\npool.submit(() -&gt; { return racineCarrePrecise(3,100000); } );\r\n                    <\/code><\/pre>\n<p class=\"fragment\">Mais alors comment r\u00e9cup\u00e9rer la valeur de retour des fonctions ?<\/p>\n<\/section>\n<section>\n<pre><code class=\"java\" data-trim=\"\">\r\nExecutorService pool = Executors.newFixedThreadPool(2);\r\nBigDecimal r2 = pool.submit(() -&gt; racineCarrePrecise(2,10000););\r\nBigDecimal r3 = pool.submit(() -&gt; racineCarrePrecise(3,100000););\r\nSystem.out.println(r2);\r\nSystem.out.println(r3);\r\n                    <\/code><\/pre>\n<p>Probl\u00e8me ? <span class=\"fragment\">la fonction <code>submit<\/code> retourne tout de suite mais la t\u00e2che \u00e0 effectuer prend du temps et le r\u00e9sultat sera connu dans le <b>futur<\/b><\/span><\/p>\n<\/section>\n<section>\n<h2>la classe du <code>Turfu<\/code><\/h2>\n<pre><code class=\"java\" data-trim=\"\">\r\nExecutorService pool = Executors.newFixedThreadPool(2);\r\nFuture&lt;BigDecimal&gt; r2 = pool.submit(()-&gt;racineCarrePrecise(2,10000));\r\nFuture&lt;BigDecimal&gt; r3 = pool.submit(()-&gt;racineCarrePrecise(3,100000));\r\nSystem.out.println(r2.get());\r\nif(r3.isDone())\r\n  System.out.println(r3.get());\r\nelse\r\n  r3.cancel(true);\r\n                    <\/code><\/pre>\n<p><a href=\"https:\/\/repl.it\/EDt9\/3\" target=\"_blank\" rel=\"noopener\"><i class=\"fa fa-play\" aria-hidden=\"true\"><\/i>run it!<\/a><\/p>\n<p class=\"fragment\">Un objet <code>Future<\/code> repr\u00e9sent un objet qui est le r\u00e9sultat d&#8217;une fonction asynchrone.<small><\/small><\/p>\n<ul>\n<li class=\"fragment\"><code>V get()<\/code> : attend que le r\u00e9sultat soit disponnible, puis le retourne<\/li>\n<li class=\"fragment\"><code>isDone()<\/code> : retourne <code>true<\/code> si le r\u00e9sultat est disponnible<\/li>\n<li class=\"fragment\"><code>cancel(boolean interrupt)<\/code> : annule le calcul (force l&#8217;interruption si <code>interrupt<\/code> est <code>true<\/code>)<\/li>\n<\/ul>\n<p><small><\/small>&nbsp;<\/p>\n<\/section>\n<section>\n<h3>Interface <code>ScheduledExecutorService<\/code><\/h3>\n<p>Ajoute des notions temporelles (de planifications). <a href=\"https:\/\/docs.oracle.com\/javase\/8\/docs\/api\/java\/util\/concurrent\/ScheduledExecutorService.html\" target=\"_blank\" rel=\"noopener\"><i class=\"fa fa-book\" aria-hidden=\"true\"><\/i>doc<\/a><\/p>\n<\/section>\n<section>\n<h3>Classes et interfaces autour de <code>Future&lt;T&gt;<\/code><\/h3>\n<p><img decoding=\"async\" class=\"stretch\" src=\"https:\/\/pagesperso.lip6.fr\/Maria.Gradinariu\/sites\/Maria.Gradinariu\/IMG\/html\/c8-figures\/classe-future.png\" alt=\"\" \/><\/section>\n<\/section>\n<section>\n<section class=\"toc-pause\">\n<h1>Acc\u00e8s Concurrents et Synchronisation<\/h1>\n<\/section>\n<section>\n<h3>Probl\u00e8mes li\u00e9s au processeur<\/h3>\n<p>&nbsp;<\/p>\n<ul>\n<li class=\"fragment\">certaines variables peuvent \u00eatre stock\u00e9es dans des registres pour \u00e9viter les aller-retour \u00e0 la m\u00e9moire<\/li>\n<li class=\"fragment\">les instructions sont r\u00e9-ordonnanc\u00e9es \u00e0 l&#8217;int\u00e9rieur d&#8217;un thread pour de meilleures performances<\/li>\n<li class=\"fragment\">Les long et double sont charg\u00e9s en 2 fois sur une machine 32bit<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<\/section>\n<section>\n<pre><code class=\"java\" data-trim=\"\">\r\npublic\u00a0class\u00a0A\u00a0implements\u00a0Runnable\u00a0{\r\n\u00a0\u00a0public\u00a0boolean\u00a0start; \/\/ false\r\n\u00a0\u00a0public\u00a0int\u00a0value;\r\n\u00a0\u00a0public\u00a0void\u00a0run()\u00a0{\r\n\u00a0\u00a0\u00a0\u00a0while(!this.start)\u00a0;\u00a0\/\/\u00a0attente\u00a0active\r\n\u00a0\u00a0\u00a0\u00a0System.out.println(value);\u00a0\/\/ jamais atteint\r\n\u00a0\u00a0}\r\n}\r\n<\/code><\/pre>\n<pre><code class=\"java\" data-trim=\"\">\r\npublic\u00a0void\u00a0doSomething(A\u00a0a)\u00a0{\r\n\u00a0\u00a0a.value\u00a0=\u00a03;\r\n\u00a0\u00a0a.start = true;\r\n}\r\n<\/code><\/pre>\n<div class=\"fragment\"><i class=\"fa fa-arrow-right\" aria-hidden=\"true\"><\/i><code>start<\/code> n&#8217;est pas mise \u00e0 jour dans la m\u00e9moire centrale<\/div>\n<\/section>\n<section>\n<pre><code class=\"java\" data-trim=\"\">\r\npublic\u00a0class\u00a0A\u00a0implements\u00a0Runnable\u00a0{\r\n\u00a0\u00a0public\u00a0boolean\u00a0start; \/\/ false\r\n\u00a0\u00a0public\u00a0int\u00a0value;\r\n\u00a0\u00a0public\u00a0void\u00a0run()\u00a0{\r\n\u00a0\u00a0\u00a0\u00a0while(!this.start)\u00a0;\u00a0\/\/\u00a0attente\u00a0active\r\n\u00a0\u00a0\u00a0\u00a0System.out.println(value);\u00a0\/\/\u00a0affiche\u00a00\r\n\u00a0\u00a0}\r\n}\r\n<\/code><\/pre>\n<pre><code class=\"java\" data-trim=\"\">\r\npublic\u00a0void\u00a0doSomething(A\u00a0a)\u00a0{\r\n\u00a0\u00a0a.value\u00a0=\u00a03;\r\n\u00a0\u00a0a.start = true;\r\n}\r\n<\/code><\/pre>\n<div class=\"fragment\"><i class=\"fa fa-arrow-right\" aria-hidden=\"true\"><\/i>R\u00e9ordonnancement<\/div>\n<pre class=\"fragment\"><code class=\"java\" data-trim=\"\">\r\n\r\na.start = true;\r\na.value\u00a0=\u00a03;\r\n\r\n<\/code><\/pre>\n<\/section>\n<section>\n<h3>Le mot cl\u00e9 <code>volatile<\/code><\/h3>\n<p>Il est utilis\u00e9 comme un modificateur de champ. Il emp\u00eache les probl\u00e8mes li\u00e9s \u00e0 l&#8217;optimisation.<\/p>\n<ul>\n<li class=\"fragment\">Assure la coh\u00e9rence entre la m\u00e9moire de travail et la m\u00e9moire principale (pas de cache possible). La mise \u00e0 jour est forc\u00e9e \u00e0 chaque lecture\/\u00e9criture pour prendre en compte les derni\u00e8res modifications<\/li>\n<li class=\"fragment\">Impose une barri\u00e8re m\u00e9moire. Interdit le r\u00e9ordonnancement entre les variables volatiles et les autres<\/li>\n<li class=\"fragment\">Assure l&#8217;atomicit\u00e9 de la lecture et de l&#8217;\u00e9criture des variables de type double et long<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<\/section>\n<section>\n<h2>Acc\u00e8s Concurrents<\/h2>\n<p>Ex\u00e9cution d&#8217;op\u00e9rations en parall\u00e8le =&gt; probl\u00e8mes lors de l&#8217;acc\u00e8s \u00e0 une resource. <b>M\u00eame si le CPU n&#8217;a qu&#8217;un seul coeur!!<\/b><\/p>\n<\/section>\n<section>\n<h2>Exemple d&#8217;acc\u00e8s concurrents<\/h2>\n<pre><code class=\"java\" data-trim=\"\">\r\n\r\nclass Account{\r\n    private int balance;\r\n    public Account(int b){\r\n        balance=b;\r\n    }\r\n    public boolean draw(int x) {\r\n        if(balance &lt; x) return false;\r\n        balance -= x;\r\n        return true;\r\n    }\r\n    public int getBalance() { return balance; }\r\n}\r\n<\/code><\/pre>\n<pre><code class=\"java\" data-trim=\"\">\r\nAccount a = new Account(30);\r\nRunnable r = () -&gt; { while(a.draw(1)); };\r\nThread t1 = new Thread(r); t1.start();\r\nThread t2 = new Thread(r); t2.start();\r\nt1.join();\r\nSystem.out.println(a.getBalance());\r\n\r\n<\/code><\/pre>\n<p><a class=\"fragment\" href=\"https:\/\/repl.it\/EEPi\" target=\"_blank\" rel=\"noopener\"><i class=\"fa fa-play\" aria-hidden=\"true\"><\/i>run it!<\/a><\/section>\n<section>\n<h3>Probl\u00e8me<\/h3>\n<p><object data=\"https:\/\/pagesperso.lip6.fr\/Maria.Gradinariu\/sites\/Maria.Gradinariu\/IMG\/html\/c8-figures\/acces-concurrents.svg\" type=\"image\/svg+xml\" width=\"300\" height=\"150\" data-mce-fragment=\"1\"><\/object>Si <code>balance<\/code> vaut initialement 1, cette ex\u00e9cution permet malgr\u00e9 tout de retirer 2, et d&#8217;obtenir une balance n\u00e9gative.<\/p>\n<\/section>\n<section>\n<h2>Exclusion Mutuelle<\/h2>\n<p>M\u00eame si chaque instruction de base est atomique, impossible d&#8217;assurer qu&#8217;un thread ne \u00ab perdra \u00bb pas le processeur entre deux instructions.<\/p>\n<p>On ne peut \u00ab que \u00bb exclure mutuellement plusieurs threads, gr\u00e2ce \u00e0 la notion de moniteur<\/p>\n<\/section>\n<section>\n<h2>Les moniteurs<\/h2>\n<p>Chaque <code>Object<\/code> est un moniteur (ou moniteur verrou). Ce moniteur sert \u00e0 la synchronisation des threads, l&#8217;acc\u00e8s exlusif \u00e0 l&#8217;\u00e9tat d&#8217;un objet.<\/p>\n<p class=\"fragment\">Un thread peut <b>acqui\u00e9rir<\/b> un verrou lorsqu&#8217;il veut un acc\u00e8s exclusif \u00e0 une donn\u00e9e, puis le <b>lib\u00e9rer<\/b> lorsqu&#8217;il a termin\u00e9. Pendant ce temps, on dit qu&#8217;il <b>poss\u00e8de<\/b> ce verrou.<\/p>\n<p class=\"fragment\"><i class=\"fa fa-lock\" aria-hidden=\"true\"><\/i>Lorsqu&#8217;un thread poss\u00e8de un v\u00e9rrou, <b>aucun autre thread ne peut l&#8217;acqui\u00e9rir<\/b>. Un autre thread qui essaie de l&#8217;acqu\u00e9rir attend que le verrou se lib\u00e8re.<\/p>\n<p class=\"fragment\"><i class=\"fa fa-unlock\" aria-hidden=\"true\"><\/i>L&#8217;action de lib\u00e8rer un verrou se produit <b>strictement avant<\/b> toute autre acquisition.<\/p>\n<\/section>\n<section>\n<h3>Acquisition d&#8217;un verrou<\/h3>\n<p>L&#8217;acquisition du verrou d&#8217;un moniteur se fait avec le mot cl\u00e9 <code>synchronized<\/code><\/p>\n<pre><code class=\"java\" data-trim=\"\">\r\nsynchronized\u00a0(monitor)\u00a0{\r\n    \/\/\u00a0bloc\u00a0prot\u00e9g\u00e9\u00a0par\u00a0monitor\r\n}\r\n<\/code><\/pre>\n<pre><code class=\"java\" data-trim=\"\">\r\n\r\nclass Account{\r\n    private final Object lock = new Object();\r\n    private int balance;\r\n    public Account(int b){\r\n        balance=b;\r\n    }\r\n    public boolean draw(int x) {\r\n        synchronized(lock) {\r\n            if(balance &lt; x) return false;\r\n            balance -= x;\r\n            return true;\r\n        }\r\n    }\r\n    public int getBalance() { synchronized(lock) { return balance; } }\r\n}\r\n<\/code><\/pre>\n<\/section>\n<section>\n<h2>Ex\u00e9cution possible<\/h2>\n<p><object data=\"https:\/\/pagesperso.lip6.fr\/Maria.Gradinariu\/sites\/Maria.Gradinariu\/IMG\/html\/c8-figures\/acces-concurrents-lock.svg\" type=\"image\/svg+xml\" width=\"300\" height=\"150\" data-mce-fragment=\"1\"><\/object><\/section>\n<section>\n<h2>M\u00e9thode synchronized<\/h2>\n<p>On peut utiliser l&#8217;objet courant <code>this<\/code> comme moniteur<\/p>\n<pre class=\"fragment hide-with-next-fragment\"><code class=\"java\" data-trim=\"\">\r\n\r\nclass Account{\r\n    private int balance;\r\n    public Account(int b){\r\n        balance=b;\r\n    }\r\n    public boolean draw(int x) {\r\n        synchronized(this) {\r\n            if(balance &lt; x) return false;\r\n            balance -= x;\r\n            return true;\r\n        }\r\n    }\r\n    public int getBalance() { synchronized(this) { return balance; } }\r\n}\r\n<\/code><\/pre>\n<pre class=\"fragment hide-with-next-fragment\"><code class=\"java\" data-trim=\"\">\r\n\r\nclass Account{\r\n    private int balance;\r\n    public Account(int b){\r\n        balance=b;\r\n    }\r\n    public synchronized boolean draw(int x) {\r\n        if(balance &lt; x) return false;\r\n        balance -= x;\r\n        return true;\r\n    }\r\n    public synchronized int getBalance() { return balance; }\r\n}\r\n<\/code><\/pre>\n<pre class=\"fragment hide-with-next-fragment\"><code class=\"java\" data-trim=\"\">\r\n\r\nclass Account{\r\n    private int balance;\r\n    public Account(int b){\r\n        balance=b;\r\n    }\r\n    public synchronized boolean draw(int x) {\r\n        if(balance &lt; x) return false;\r\n        if(x &lt; 0) return false;\r\n        balance -= x;\r\n        return true;\r\n    }\r\n    public synchronized boolean add(int x) {\r\n        if(x &lt; 0) return false;\r\n        balance += x;\r\n        return true;\r\n    }\r\n    public synchronized int getBalance() { return balance; }\r\n}\r\n                <\/code><\/pre>\n<pre class=\"fragment\"><code class=\"java\" data-trim=\"\">\r\n\r\nclass Account{\r\n    private volatile int balance;\r\n    public Account(int b){\r\n        balance=b;\r\n    }\r\n    public synchronized boolean draw(int x) {\r\n        if(balance &lt; x) return false;\r\n        if(x &lt; 0) return false;\r\n        balance -= x;\r\n        return true;\r\n    }\r\n    public synchronized boolean add(int x) {\r\n        if(x &lt; 0) return false;\r\n        balance += x;\r\n        return true;\r\n    }\r\n    public int getBalance() { return balance; }\r\n}\r\n                <\/code><\/pre>\n<\/section>\n<section>\n<h3>Synchronized <code>this<\/code><\/h3>\n<p>Cependant il est pr\u00e9f\u00e9rable d&#8217;utiliser un moniteur diff\u00e9rent de <code>this<\/code>.<\/p>\n<ul>\n<li class=\"fragment\"><code>this<\/code> est peut-etre d\u00e9j\u00e0 utilis\u00e9 comme moniteur par une autre partie du code<\/li>\n<li class=\"fragment\">cela permet de d\u00e9finir la zone d&#8217;exclusion mutuelle de mani\u00e8re plus pr\u00e9cise<\/li>\n<li class=\"fragment\">cela permet de d\u00e9finir des moniteurs diff\u00e9rents pour des resources diff\u00e9rentes<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<\/section>\n<section>\n<h2>Un moniteur par resource<\/h2>\n<pre><code class=\"java\" data-trim=\"\">\r\n\r\nclass Account{\r\n    private final Object balanceLock = new Object();\r\n    private final Object nameLock = new Object();\r\n    private int balance;\r\n    private String name;\r\n    private List&lt;String&gt; previousNames =\r\n        new ArrayList&lt;String&gt;();\r\n    public Account(int b){\r\n        balance=b;\r\n    }\r\n    public boolean draw(int x) {\r\n        synchronized(balanceLock) {\r\n            if(balance &lt; x) return false;\r\n            balance -= x;\r\n            return true;\r\n        }\r\n    }\r\n    public void setName(String name) {\r\n        synchronized(nameLock) {\r\n            previousNames.add(name);\r\n            this.name = name;\r\n        }\r\n    }\r\n}\r\n\r\n<\/code><\/pre>\n<\/section>\n<section>\n<h3>Les moniteurs sont r\u00e9entrants<\/h3>\n<p>Si un thread d\u00e9tient un moniteur <code>m<\/code> alors il peut ex\u00e9cuter d&#8217;autres section de code n\u00e9cessitant l&#8217;acquisition de <code>m<\/code><\/p>\n<pre class=\"fragment\"><code class=\"java\" data-trim=\"\">\r\nclass Account{\r\n    private final Object lock = new Object();\r\n    private int balance;\r\n    public Account(int b){\r\n        balance=b;\r\n    }\r\n    public boolean draw(int x) {\r\n        synchronized(lock) { \/\/ acquiert lock\r\n            if(getBalance() &lt; x) \/\/ appelle getBalance()\r\n                return false;\r\n            balance -= x;\r\n            return true;\r\n        }\r\n    }\r\n    public int getBalance() {\r\n        synchronized(lock) { \/\/ lock d\u00e9j\u00e0 acquit =&gt; OK\r\n            return balance;\r\n        }\r\n    }\r\n}\r\n                <\/code><\/pre>\n<\/section>\n<section>Un objet dont les m\u00e9thodes peuvent \u00eatre appel\u00e9es par des threads diff\u00e9rents et qui fonctionne correctement est dit <b>thread-safe<\/b>.<\/p>\n<\/section>\n<section>\n<h2>Attention \u00e0 l&#8217;inter-blocage<\/h2>\n<pre class=\"fragment\"><code class=\"java\" data-trim=\"\">\r\nclass Account{\r\n    private final Object lock = new Object();\r\n    private int balance;\r\n    public Account(int b){\r\n        balance=b;\r\n    }\r\n    public boolean draw(int x) {\r\n        synchronized(lock) {\r\n            if(balance &lt; x) return false;\r\n            balance -= x;\r\n            return true;\r\n        }\r\n    }\r\n    public boolean transfertTo(Account account, int amount) {\r\n        synchronized(lock) {\r\n            synchronized(account.lock) {\r\n                if(!draw(amount)) return false;\r\n                account.add(amount);\r\n                return true;\r\n            }\r\n        }\r\n    }\r\n}\r\n                <\/code><\/pre>\n<\/section>\n<section>\n<h3>Attention \u00e0 l&#8217;inter-blocage<\/h3>\n<pre class=\"\"><code class=\"java\" data-trim=\"\">\r\nAccount a = new Account(100);\r\nAccount b = new Account(100);\r\n\r\n\r\nThread t1 = new Thread(() -&gt; {\r\n    a.transfertTo(b, 50);\r\n});\r\nt1.start();\r\nThread t2 = new Thread(() -&gt; {\r\n    b.transfertTo(a, 50);\r\n});\r\nt1.join(); \/\/ ne termine jamais\r\nt2.join();\r\nSystem.out.println(a.getBalance());\r\n\r\n<\/code><\/pre>\n<p><object data=\"https:\/\/pagesperso.lip6.fr\/Maria.Gradinariu\/sites\/Maria.Gradinariu\/IMG\/html\/c8-figures\/deadlock.svg\" type=\"image\/svg+xml\" width=\"300\" height=\"150\" data-mce-fragment=\"1\"><\/object><\/section>\n<section>\n<h2>Synchronisation et m\u00e9moire<\/h2>\n<p>&nbsp;<\/p>\n<ul>\n<li class=\"fragment\">Le rel\u00e2chement d&#8217;un moniteur (release) force l&#8217;\u00e9criture dans la m\u00e9moire principale de tout ce qui a \u00e9t\u00e9 modifi\u00e9 dans le cache (registres) avant ou pendant le bloc synchronis\u00e9<\/li>\n<li class=\"fragment\">L&#8217;acquisition d&#8217;un moniteur (acquire) invalide le cache (registres) et force la relecture depuis la m\u00e9moire principale<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<p class=\"fragment\">La notion d&#8217;atomicit\u00e9 tend \u00e0 garantir que l&#8217;\u00e9tat de la m\u00e9moire sera coh\u00e9rent<\/p>\n<p class=\"fragment\">La notion d&#8217;exclusion mutuelle (synchronized) ne fait qu&#8217;assurer que du code n&#8217;aura pas acc\u00e8s \u00e0 un \u00e9tat de la m\u00e9moire incoh\u00e9rent<\/p>\n<\/section>\n<section>\n<h3>Synchronisation et notification<\/h3>\n<p>On a vu les m\u00e9thodes <code>sleep<\/code>, resp. <code>join<\/code>, qui permettent d&#8217;attendre un temps donn\u00e9, resp. la terminaison d&#8217;un thread.<\/p>\n<p>Il est aussi possible pour un thread d&#8217;attendre une notification avec la m\u00e9thode <code>wait<\/code>.<\/p>\n<\/section>\n<section>\n<h3><code>wait\/notify<\/code><\/h3>\n<p>Un thread <code>A<\/code> peut appel\u00e9 la m\u00e9thode <code>o.wait()<\/code> sur un objet quelconque <code>o<\/code>. Pour cela le thread <b>doit d\u00e9tenir le verrou du moniteur <code>o<\/code><\/b>.<\/p>\n<p class=\"fragment\">Apr\u00e8s l&#8217;appelle de <code>wait<\/code>:<\/p>\n<ul>\n<li class=\"fragment\">le thread <code>A<\/code> lib\u00e8re le verrou de <code>o<\/code><\/li>\n<li class=\"fragment\">le thread attend<\/li>\n<li class=\"fragment\">Lorsque un autre thread envoie une notification en utilisant <code>o<\/code> avec la m\u00e9thode <code>o.notify()<\/code> ou <code>o.notifyAll()<\/code>, le thread <code>A<\/code> est r\u00e9v\u00e9ill\u00e9 et tente \u00e0 nouveau d&#8217;acqui\u00e9rir le verrou.<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<\/section>\n<section>\n<h3><code>wait\/notify<\/code><\/h3>\n<p>Pour pouvoir appeler <code>notify<\/code> ou <code>notifyAll<\/code> sur un objet <code>o<\/code>, un thread doit d\u00e9tenir le verrou de <code>o<\/code>.<\/p>\n<p class=\"fragment\">Lorsqu&#8217;un thread <code>B<\/code> appelle de <code>o.notify()<\/code> : un seul thread en attente sur l&#8217;objet <code>o<\/code> (chosi al\u00e9atoirement) est r\u00e9veill\u00e9.<\/p>\n<p class=\"fragment\">Lorsqu&#8217;un thread <code>B<\/code> appelle de <code>o.notifyAll()<\/code> : tous les threads en attente sur l&#8217;objet <code>o<\/code> sont r\u00e9veill\u00e9s. Ils sont alors en comp\u00e9tition pour acqu\u00e9rir le verrou de <code>o<\/code>.<\/p>\n<\/section>\n<section>\n<h3>Exemple typique<\/h3>\n<p>Toujours faire les <code>wait()<\/code> dans une boucle v\u00e9rifiant la condition que l&#8217;on souhaite. Apr\u00e8s le r\u00e9veil et la r\u00e9-acquisition du moniteur, cela assure que la condition requise est toujours valide! En particulier, on sait qu&#8217;elle n&#8217;a pas \u00e9t\u00e9 consomm\u00e9e par un tiers.<\/p>\n<pre><code class=\"java\" data-trim=\"\">\r\n\/\/\u00a0code\u00a0des\u00a0processus\u00a0l\u00e9gers\r\n\/\/\u00a0int\u00e9ress\u00e9s\u00a0par\u00a0les\u00a0\u00e9v\u00e9nements\u00a0\r\nsynchronized\u00a0(o)\u00a0{\r\n\u00a0\u00a0while\u00a0(ok==0)\u00a0{\r\n\u00a0\u00a0\u00a0\u00a0o.wait();\r\n\u00a0\u00a0}\r\n\u00a0\u00a0ok--;\r\n}\r\ntraitement();\r\n<\/code><\/pre>\n<pre><code class=\"java\" data-trim=\"\">\r\n\/\/\u00a0code\u00a0du\u00a0processus\u00a0l\u00e9ger\r\n\/\/\u00a0qui\u00a0signale\u00a0les\u00a0\u00e9v\u00e9nements\u00a0\r\nsynchronized\u00a0(o)\u00a0{\r\n\u00a0\u00a0ok++;\r\n\u00a0\u00a0o.notify();\r\n}\r\n<\/code><\/pre>\n<\/section>\n<section>\n<h2>wait()<\/h2>\n<p>Le m\u00e9thode <code>wait()<\/code> &#8220;attend&#8221; donc le thread qui l&#8217;appelle peut \u00eatre interrompu dans cette attente (elle lance une exception <code>InterruptedException<\/code>)<\/p>\n<p class=\"fragment\">Comme les autres m\u00e9thodes de synchronisation <code>Thread.join<\/code>, <code>Future&lt;T&gt;.get<\/code>, &#8230;. elle accepte un param\u00e8tre <code>long<\/code> qui d\u00e9finit l&#8217;attente maximale autoris\u00e9e.<\/p>\n<\/section>\n<\/section>\n<section>\n<section class=\"toc-pause\">\n<h1>Probl\u00e8mes<\/h1>\n<\/section>\n<section>\n<h2>Data Race<\/h2>\n<p>C&#8217;est lorsqu&#8217;il peut y avoir une &#8220;course aux donn\u00e9es&#8221;. C&#8217;est-\u00e0-dire lorsque : (a) un thread \u00e9crit dans une variable (b) un autre thread lit dans cette variable (c) l&#8217;\u00e9criture et la lecture ne sont pas ordonn\u00e9es explicitement par synchronisation.<\/p>\n<pre><code class=\"java\" data-trim=\"\">\r\n  public\u00a0class\u00a0SimpleDataRace\u00a0{\r\n  \u00a0\u00a0static\u00a0int\u00a0a\u00a0=\u00a00;\r\n  \u00a0\u00a0public\u00a0static\u00a0void\u00a0main(String[]\u00a0args)\u00a0{\r\n  \u00a0\u00a0\u00a0\u00a0new\u00a0Thread(()\u00a0-&gt; { System.out.println(a); }).start();\r\n  \u00a0\u00a0\u00a0\u00a0a\u00a0=\u00a01;\r\n  \u00a0\u00a0}\u00a0\/*\u00a0Peut\u00a0afficher\u00a01\u00a0comme\u00a00.\u00a0*\/\r\n  }\r\n  <\/code><\/pre>\n<\/section>\n<section>\n<h2>Race Condition<\/h2>\n<pre><code class=\"java\" data-trim=\"\">\r\n  class FileDownloader {\r\n       setFile(File file)   { ... }\r\n       isAuthorized(User u) { ... }\r\n       download(User u)     { ... }\r\n  }\r\n  <\/code><\/pre>\n<pre><code class=\"java\" data-trim=\"\">\r\n\r\n  doDownload(User u, FileDownloader f){\r\n      if(f.isAutgorized()){\r\n          f.download(u);\r\n      }\r\n  }\r\n\r\n  <\/code><\/pre>\n<p>f n&#8217;est pas immuable donc si un autre thread appelle setFile entre isAuthorized et download(), alors un fichier potentiellement priv\u00e9 sera envoy\u00e9. M\u00eame si <code>FileDownloader<\/code> est thread-safe.<\/p>\n<\/section>\n<section><img decoding=\"async\" class=\"stretch\" src=\"https:\/\/pagesperso.lip6.fr\/Maria.Gradinariu\/sites\/Maria.Gradinariu\/IMG\/html\/c8-figures\/cow.png\" alt=\"\" \/>on d\u00e9couvre encore de tels bugs : <a href=\"https:\/\/git.kernel.org\/cgit\/linux\/kernel\/git\/torvalds\/linux.git\/commit\/?id=19be0eaffa3ac7d8eb6784ad9bdbc7d67ed8e619\" target=\"_blank\" rel=\"noopener\">Dirty COW<\/a> &#8211; <a href=\"https:\/\/www.youtube.com\/watch?v=kEsshExn7aE\" target=\"_blank\" rel=\"noopener\">vid\u00e9o explicative<\/a><\/p>\n<p><a href=\"https:\/\/repl.it\/EEqZ\/3\" target=\"_blank\" rel=\"noopener\">Vue simplifi\u00e9e du bug!<\/a><\/p>\n<\/section>\n<\/section>\n<section>\n<section class=\"toc-pause\">\n<h1>Serveur Multithread<\/h1>\n<\/section>\n<section>\n<h3>Architecture d&#8217;un serveur acceptant plusieurs connexion<\/h3>\n<p>Le plus simple est d&#8217;\u00e9couter l&#8217;arriv\u00e9e de nouvelles connexions dans le thread principal.<\/p>\n<p class=\"fragment\">Pour pouvoir accepter de nouvelle connexion, il ne faut pas que l&#8217;\u00e9coute d&#8217;une socket particuli\u00e8re s&#8217;ex\u00e9cute sur le thread principal<\/p>\n<p class=\"fragment\">Donc lorsqu&#8217;un connexion arrive, il faut que le serveur d\u00e9l\u00e8gue la gestion de cette connexion \u00e0 un autre thread.<\/p>\n<\/section>\n<section>\n<h2>Exemple Basique<\/h2>\n<pre><code class=\"java\" data-trim=\"\">\r\nimport java.util.*;\r\nimport java.net.*;\r\nimport java.io.*;\r\nclass Server {\r\n\r\npublic static void main(String[] args) throws Exception {\r\n\r\n  ServerSocket serverSocket = new ServerSocket(3014);\r\n\r\n  while(true) {\r\n\r\n    Socket clientSocket = serverSocket.accept();\r\n\r\n    \/\/ on a une nouvelle connexion, on la traite.\r\n    PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);\r\n    BufferedReader in =\r\n        new BufferedReader(\r\n        new InputStreamReader(clientSocket.getInputStream())\r\n        );\r\n\r\n    System.out.println(\"connection of \"+\r\n      clientSocket.getRemoteSocketAddress());\r\n\r\n    String inputLine = \"\";\r\n    while ((inputLine = in.readLine()) != null) {\r\n      System.out.println(inputLine);\r\n      if (inputLine.equals(\"Bye\"))\r\n      {\r\n        out.println(\"Bye\");\r\n        break;\r\n      }\r\n      out.println(\"You said \"+inputLine);\r\n    }\r\n    System.out.println(\"disconnection of \"+\r\n      clientSocket.getRemoteSocketAddress());\r\n\r\n    out.close();\r\n    in.close();\r\n    clientSocket.close();\r\n\r\n    \/\/ le client est parti, on peut accepter un nouvelle connexion\r\n\r\n  }\r\n}\r\n}\r\n<\/code><\/pre>\n<\/section>\n<section>\n<h2>Exemple Basique<\/h2>\n<pre class=\"fragment hide-with-next-fragment\"><code class=\"java\" data-trim=\"\">\r\n\r\nclass Server {\r\npublic static void main(String[] args) throws Exception {\r\n  ServerSocket serverSocket = new ServerSocket(3014);\r\n  while(true) {\r\n    Socket clientSocket = serverSocket.accept();\r\n\r\n    \/\/ on a une nouvelle connexion, on la traite.\r\n    \/\/ ... code qui g\u00e8re un client\r\n    \/\/ le client est parti, on peut accepter un nouvelle connexion\r\n\r\n  }\r\n}\r\n}\r\n<\/code><\/pre>\n<pre class=\"fragment\"><code class=\"java\" data-trim=\"\">\r\n\r\nclass Server {\r\npublic static void main(String[] args) throws Exception {\r\n  ServerSocket serverSocket = new ServerSocket(3014);\r\n  while(true) {\r\n    Socket clientSocket = serverSocket.accept();\r\n\r\n    \/\/ on a une nouvelle connexion, on la traite.\r\n    \/\/ ... code qui g\u00e8re un client\r\n    \/\/ ... contient des fonctions bloquantes!!!\r\n    \/\/ le client est parti, on peut accepter un nouvelle connexion\r\n\r\n  }\r\n}\r\n}\r\n<\/code><\/pre>\n<\/section>\n<section>\n<h2>Solution Basique<\/h2>\n<pre class=\"\"><code class=\"java\" data-trim=\"\">\r\n\r\nclass Server {\r\npublic static void main(String[] args) throws Exception {\r\n  ServerSocket serverSocket = new ServerSocket(3014);\r\n  while(true) {\r\n    Socket clientSocket = serverSocket.accept();\r\n\r\n    \/\/ on a une nouvelle connexion, on la traite.\r\n    new Thread(() -&gt; {\r\n      \/\/ ... code qui g\u00e8re un client\r\n    }).start();\r\n\r\n    \/\/ le client est g\u00e9r\u00e9 dans un thread s\u00e9par\u00e9,\r\n    \/\/ on peut accepter un nouvelle connexion\r\n\r\n  }\r\n}\r\n}\r\n<\/code><\/pre>\n<\/section>\n<section>\n<h2>Solution avec un executor<\/h2>\n<pre class=\"\"><code class=\"java\" data-trim=\"\">\r\nimport java.util.concurrent.*;\r\nclass Server {\r\npublic static void main(String[] args) throws Exception {\r\n  ServerSocket serverSocket = new ServerSocket(3014);\r\n  ExecutorService executor = Executors.newFixedThreadPool(30);\r\n  while(true) {\r\n    Socket clientSocket = serverSocket.accept();\r\n\r\n    \/\/ on a une nouvelle connexion, on la traite.\r\n    executor.submit(() -&gt; {\r\n      \/\/ ... code qui g\u00e8re un client\r\n    });\r\n\r\n    \/\/ le client est g\u00e9r\u00e9 s\u00e9par\u00e9ment,\r\n    \/\/ on peut accepter un nouvelle connexion\r\n\r\n  }\r\n}\r\n}\r\n<\/code><\/pre>\n<p>S&#8217;il y a trop de connexions, elles seront mises en attente <b>par l&#8217;ex\u00e9cutor<\/b>, on n&#8217;arr\u00eate jamais d&#8217;accepter de nouvelles connexions.<\/p>\n<\/section>\n<section>\n<h2>Solution Compl\u00e8te<\/h2>\n<p>Comme la gestion d&#8217;un client peut \u00eatre assez complexe, \u00e7a vaut le coup de cr\u00e9er une classe d\u00e9di\u00e9e.<\/p>\n<pre><code class=\"java\" data-trim=\"\">\r\nclass ClientHandler implements Runnable {\r\n  Socket client;\r\n  ClientHandler(Socket s) { client = s; }\r\n\r\n  @Override\r\n  public void run() {\r\n    \/\/ ... code qui g\u00e8re un client\r\n  }\r\n}\r\n<\/code><\/pre>\n<\/section>\n<section>\n<h2>Solution Compl\u00e8te<\/h2>\n<p>Comme la gestion d&#8217;un client peut \u00eatre assez complexe, \u00e7a vaut le coup de cr\u00e9er une classe d\u00e9di\u00e9e.<\/p>\n<pre class=\"\"><code class=\"java\" data-trim=\"\">\r\nimport java.util.concurrent.*;\r\nclass Server {\r\npublic static void main(String[] args) throws Exception {\r\n  ServerSocket serverSocket = new ServerSocket(3014);\r\n  ExecutorService executor = Executors.newFixedThreadPool(30);\r\n  while(true) {\r\n    Socket clientSocket = serverSocket.accept();\r\n\r\n    \/\/ on a une nouvelle connexion, on la traite.\r\n    executor.submit(new ClientHandler(clientSocket));\r\n\r\n    \/\/ le client est g\u00e9r\u00e9 s\u00e9par\u00e9ment,\r\n    \/\/ on peut accepter un nouvelle connexion\r\n\r\n  }\r\n}\r\n}<\/code><\/pre>\n<\/section>\n<\/section>\n","protected":false},"excerpt":{"rendered":"<p>Introduction Dans une ex\u00e9cution s\u00e9quentielle, une grande partie du temps est pass\u00e9e \u00e0 attendre.Exemple: lors de l&#8217;attente de r\u00e9ception d&#8217;un message dans un socket, lors de la lecture d&#8217;un fichier, &#8230; Lecture de deux sockets : Socket s1 = new Socket(host, port); Socket s2 = new Socket(host2, port2); InputStream in1 = s1.getInputStream(); InputStream in2 = [&hellip;]<\/p>\n","protected":false},"author":55,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-63","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/wp-systeme.lip6.fr\/potop-butucaru\/wp-json\/wp\/v2\/posts\/63","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wp-systeme.lip6.fr\/potop-butucaru\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wp-systeme.lip6.fr\/potop-butucaru\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/wp-systeme.lip6.fr\/potop-butucaru\/wp-json\/wp\/v2\/users\/55"}],"replies":[{"embeddable":true,"href":"https:\/\/wp-systeme.lip6.fr\/potop-butucaru\/wp-json\/wp\/v2\/comments?post=63"}],"version-history":[{"count":2,"href":"https:\/\/wp-systeme.lip6.fr\/potop-butucaru\/wp-json\/wp\/v2\/posts\/63\/revisions"}],"predecessor-version":[{"id":65,"href":"https:\/\/wp-systeme.lip6.fr\/potop-butucaru\/wp-json\/wp\/v2\/posts\/63\/revisions\/65"}],"wp:attachment":[{"href":"https:\/\/wp-systeme.lip6.fr\/potop-butucaru\/wp-json\/wp\/v2\/media?parent=63"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wp-systeme.lip6.fr\/potop-butucaru\/wp-json\/wp\/v2\/categories?post=63"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wp-systeme.lip6.fr\/potop-butucaru\/wp-json\/wp\/v2\/tags?post=63"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}