Télécharger la présentation
La présentation est en train de télécharger. S'il vous plaît, attendez
Publié parRaymond Bouchard Modifié depuis plus de 8 années
1
Java – Threads & Calcul distribué Eric Blaudez (eric.baudez@u-psud.fr)| 06
2
Description Cours sur les threads & le calcul distribué Multi-threads, Multi-processes, calcul distribué Threads Introduction Cycle de vie Créer et manipuler des threads Executors ShutdownHook Gestion des sections critiques Calcul distribué Introduction Création de la partie server Création de la partie client Java - Threads & calcul distribué 2
3
Multi-threads, Multi-processes & calcul distribué Java - Threads & calcul distribué 3 Thread 1 Thread 2 Thread 4 Thread 3 Process 1 Process 2 Process 4 Process 3 Computer 1 Computer 2 Computer 4 Computer 3 Un process peut contenir plusieurs threads Une unité de calcul distribuée sur un nœud réseau peut contenir plusieurs processes et plusieurs threads
4
Multi-threads, Multi-processes & calcul distribué Java - Threads & calcul distribué 4 L'utilisation des threads, du calcul multi-processes ou encore du calcul distribué sont des stratégies de développement visant à paralléliser des calculs ou des tâches de manière à optimiser la rapidité d'exécution.
5
Multi-threads, Multi-processes & calcul distribué Le multithreading Java - Threads & calcul distribué 5 Le multithreading permet, au sein d'un même processus d'exécuter des tâches en parallèles. L'objectif est d'utiliser au mieux les architectures multi-coeurs et/ou multiprocesseurs. Les threads étant instancié dans un unique processus (un programme) ils partagent le même espace mémoire.
6
Multi-threads, Multi-processes & calcul distribué Le multi-processes Java - Threads & calcul distribué 6 A l'instar du multi-threading, l'objectif et d'utiliser la communication inter-process, pour effectuer plusieurs actions au même moment. Contrairement aux threads l'espace mémoire n'est pas facilement partagé. Si nous souhaitons utiliser une espace de mémoire partagé, il faudra initier une mémoire partagée.
7
Multi-threads, Multi-processes & calcul distribué Le calcul distribué Java - Threads & calcul distribué 7 Le calcul distribué permet l'utilisation d'un ensemble d'ordinateurs (par la biais d'un cluster par exemple) pour effectuer des calculs ou des tâches en parallèle. Généralement le calcul distribué utilise des protocoles tels que MPI (Message Passing Interface) ou des méthodes utilisant des objets partagés tels que CORBA (Common Object Request Broker Architecture), ou les Java RMI (Remote Methods Invocation).
8
Agenda - Threads Introduction Cycle de vie Créer et manipuler des threads Executors ShutdownHook Gestion des sections critiques Java - Threads & calcul distribué 8
9
Threads - Introduction Java - Threads & calcul distribué 9 Thread 1 Processus Thread 2 Espace mémoire Architecture matérielle Disque dur Processeurs … …
10
Threads - Introduction Java - Threads & calcul distribué 10 Les threads peuvent être vus comme des sous programmes évoluant au sein d'un même processus et partageant le même espace mémoire. En java, l'instanciation de threads est effectuée en utilisant la classe Thread. Cette classe fournie un ensemble de méthodes pour l'exécution, la mise en veille ou l'arrêt d'un thread.
11
Agenda - Threads Introduction Cycle de vie Créer et manipuler des threads Executorss ShutdownHook Gestion des sections critiques Java - Threads & calcul distribué 11
12
Threads - Cycle de vie Java - Threads & calcul distribué NEWRUNNABLETERMINATED 12 Thread stopped BLOCKED TIME WAITING WAITING
13
Threads - Cycle de vie Java - Threads & calcul distribué 13 NEW : dans cet état, le thread est instancié, mais n'est pas encore en cours d'exécution. Il faudra appeler la méthode start() pour passer dans l'état suivant. RUNNABLE : le thread se trouve dans cet état juste après l'appel de la méthode start(); il est placé dans une file d'attente (gérée par un ordonnanceur), puis exécuté BLOCKED : le thread est bloqué WAITING : le thread attend indéfiniment jusqu'à son réveille TIME_WAITING : le thread attend un temps défini jusqu'à son réveille TERMINATED : le thread n'est plus en cours d'exécution (l'exécution du code métier est terminé).
14
Threads - Cycle de vie Java - Threads & calcul distribué 14 public class ThreadLifeCycleExample { public static void main(String[] args) { Thread thread = new Thread(new Runnable() { @Override public void run() { for (int i = 0;i<10;i++) { System.err.print("* I:"+i+" *"); if (i % 3 == 0) { try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } } } } }); Thread.State lastState = Thread.State.TERMINATED; while(true) { Thread.State state = thread.getState(); if (lastState == state) { System.err.print("."); } else { System.err.print("\nThread State:"+state+" repeat:"); } if (state == Thread.State.NEW) { thread.start(); } else if (state == Thread.State.TERMINATED) { break; } lastState = state; } Thread State:NEW repeat: Thread State:RUNNABLE repeat:.........* I:0 * Thread State:BLOCKED repeat: Thread State:TIMED_WAITING repeat:.................. Thread State:BLOCKED repeat:* I:2 * Thread State:RUNNABLE repeat:* I:3 * Thread State:BLOCKED repeat: Thread State:TIMED_WAITING repeat:..* I:4 ** I:5 Thread State:RUNNABLE repeat: Thread State:TIMED_WAITING repeat:............... Thread State:RUNNABLE repeat:......*I:6** I:7 * Thread State:BLOCKED repeat:* I:8 * Thread State:RUNNABLE repeat:....* I:9 * Thread State:BLOCKED repeat: Thread State:TIMED_WAITING repeat:.............. Thread State:RUNNABLE repeat:..................... Thread State:TERMINATED repeat:
15
Agenda - Threads Introduction Cycle de vie Créer et manipuler des threads Executors ShutdownHook Gestion des sections critiques Java - Threads & calcul distribué 15
16
Threads – Créer & Manipuler des threads Instanciation & exécution d'un Thread Java - Threads & calcul distribué 16 La création d'un thread se fait de deux manières: En dérivant la classe Thread et en implémentant la méthode run() En dérivant de l'interface Runnable et en implémentant la méthode run() L'exécution d'un thread est faite en utilisant la méthode start(). Le code métier (instancié dans la méthode run()) sera exécuté en tâche de fond.
17
Threads – Créer & Manipuler des threads Instanciation & exécution d'un Thread Java - Threads & calcul distribué 17 MéthodeDescription void run()Si le thread est créé avec un objet de type Runnable la méthode run() de cet objet est appelé. Sinon, cette méthode ne fait rien : par défaut l'implémentation est vide, il faudra dériver la classe Thread et ré-implémenter la méthode run() pour exécuter un code métier. void start()Cette méthode permet d'exécuter le thread. API - Thread
18
Threads – Créer & Manipuler des threads Instanciation & exécution d'un Thread Java - Threads & calcul distribué 18 public class FromRunnableInterface implements Runnable { @Override public void run() { System.err.println("Run with Runnable interface"); } public class FromThreadClass extends Thread { public FromThreadClass() { } public void run() { System.err.println("Run with Thread class"); } public class ThreadInstanciation { public static void main(String[] args) { Thread fromThread = new FromThreadClass(); Thread fromRunnable = new Thread(new FromRunnableInterface()); fromThread.start(); fromRunnable.start(); } Run with Thread class Run with Runnable interface
19
Threads – Créer & Manipuler des threads Instanciation & exécution d'un Thread Java - Threads & calcul distribué 19 Le code métier (celui contenu dans la méthode run()) est exécuté à l'appel de la méthode start(). Cette méthode n'est pas bloquante, autrement dit, le flux d'exécution continu après son appel. Il est possible 'd'attendre' la fin d'un thread en utilisant la méthode join: MéthodesDescriptions void join()Attend la fin du thread (fin de la méthode run()). void join(long millis)Attend au plus millis millisecondes la fin du thread (après ce temps le flot d'exécution continu). void join(long millis, int nanos)Attend au plus millis millisecondes + nanos nanoseconds la fin du thread. API
20
Threads – Créer & Manipuler des threads Instanciation & exécution d'un Thread Java - Threads & calcul distribué 20 public class ThreadJoin { public static void main(String[] args) { Thread threadTest = new Thread( new Runnable() { @Override public void run() { System.err.println("Run thread wait 2 seconds"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.err.println("Thread ended"); } } ); System.err.println("Wait thread 500ms"); threadTest.start(); try { threadTest.join(500); } catch (InterruptedException e) { e.printStackTrace(); } System.err.println("Join finished (thread not ended)"); try { threadTest.join(); } catch (InterruptedException e) { e.printStackTrace(); } } Wait thread 500ms Run thread wait 2 seconds Join finished (thread not ended) Thread ended
21
Threads – Créer & Manipuler des threads Instanciation & exécution d'un Thread Java - Threads & calcul distribué 21 Les threads peuvent être interrompus temporairement - comme dans l'exemple précédent - en utilisant la méthode Thread.sleep. Cette méthode permet de stopper le thread pendant un temps déterminé. Ils peuvent également être arrêtés définitivement avec la méthode interrupt() MéthodesDescription static void sleep(long millis)Le thread courant est 'endormi' pendant un nombre déterminé de millisecondes. La précision de l'attente dépend de l'ordonnanceur static void sleep(long millis, int nanos) Le thread courant est 'endormi' pendant un nombre déterminé de millisecondes + de nanosecondes. La précision de l'attente dépend de l'ordonnanceur void interrupt()Interrompt le thread static boolean interrupted()Test si le thread a été interrompu. API
22
Threads – Créer & Manipuler des threads Instanciation & exécution d'un Thread Java - Threads & calcul distribué 22 MéthodesDescription static int activeCount()Donne une estimation du nombre courrant de threads, static Thread currentThread()Retourne une réference sur le thread courrant, void checkAccess()Détermines si le thread courrant (celui exécutant cette méthode) a la permission de modifier ce thread. static int enumerate(Thread[] tarray) Copie dans un tableau tous les threads actifs, long getId()Retourne l'identifiant du thread, String getName()Retourne le nom du thread, void setName(String name)Change le nom du thread, int getPriority() void setPriority(int priority) Retourne(get) la priorité ou défini(set) la priorité du thread. Thread.State getState()Retourne l'état du thread, String toString()Retourne une chaîne de caractères représentant le thread (nom, priorité, groupe), boolean isAlive()Test si un thread est en vie. API
23
Threads – Créer & Manipuler des threads Gérer les exceptions Java - Threads & calcul distribué 23 Un thread étant un sous-programme s'exécutant en tâche de fond, il est difficile d'en gérer les erreurs. Notamment lorsqu'une exception est levée sans être attrapée dans le scope du thread. Java fourni un ensemble de méthodes permettant l'accès au éventuelles exceptions levées, ou encore des méthodes permettant d'instaurer une gestionnaire d'exceptions non capturées.
24
Threads – Créer & Manipuler des threads Gérer les exceptions Java - Threads & calcul distribué 24 MéthodesDescriptions static void dumpStack()Affiche la pile d'appels du thread courant sur la sortie d'erreur standard static Map getAllStackTraces()Retourne un tableau associatif de chaque thread avec sa pile d'appels static Thread.UncaughtExceptionHandler getDefaultUncaughtExceptionHandler() Retourne le gestionnaire par défaut d'un thread se terminant à cause d'un exception non gérée StackTraceElement[] getStackTrace()Retourne une table de pile d'appels représentant un dump de la pile d'appel du thread Thread.UncaughtExceptionHandler getUncaughtExceptionHandler() Retourne le gestionnaire d'un thread se terminant à cause d'un exception non gérée static void setDefaultUncaughtExceptionHandler( Thread.UncaughtExceptionHandler eh ) Défini un gestionnaire d'erreur par défaut intervenant quand une exception non gérée est lancée par le thread void setUncaughtExceptionHandler( Thread.UncaughtExceptionHandler eh ) Défini un gestionnaire d'erreur intervenant quand une exception non gérée est lancée par le thread
25
Threads – Créer & Manipuler des threads Gérer les exceptions Java - Threads & calcul distribué 25 public class ThreadException { public static void main(String[] args) { Thread threadTest = new Thread( new Runnable() { @Override public void run() { System.err.println("Run thread"); int x = 4; for (int i = 0;i<10;i++) { x/=i; } } }); threadTest.setUncaughtExceptionHandler(new MyThreadException()); threadTest.start(); } public class MyThreadException implements UncaughtExceptionHandler { @Override public void uncaughtException(Thread arg0, Throwable arg1) { System.err.print("My thread exception handler:" + arg1.getMessage()); } Run thread My thread exception handler:/ by zero
26
Threads – Créer & Manipuler des threads Groupes de threads Java - Threads & calcul distribué 26 La classe ThreadGroup permet de grouper des threads. Dès lors il est possible d'effectuer des actions sur l'ensemble des threads se trouvant dans le groupe, comme, par exemple, les interrompre. La méthode getThreadGroup permet d'obtenir le group auquel appartient le thread.
27
Threads – Créer & Manipuler des threads Priorité d’exécution Java - Threads & calcul distribué 27 Les threads sont exécutés en tâches de fond et partagent les mêmes ressources (processeur & mémoire). Ils sont ordonnancés par la JVM. En modifiant la priorité d'un thread nous le favorisons (ou défavorisons) en terme de ressources processeurs.
28
Threads – Créer & Manipuler des threads Priorité d’exécution Java - Threads & calcul distribué 28 public static void main(String[] args) { Thread threadTest1 = new Thread( new Runnable() { @Override public void run() { System.err.println("Run thread 1"); for (int i = 0;i<15;i++) { System.err.println("["+i+"] Thread 1 priority:" +Thread.currentThread().getPriority()); } } }); Thread threadTest2 = new Thread( new Runnable() { @Override public void run() { System.err.println("Run thread 2"); for (int i = 0;i<15;i++) { System.err.println("["+ i +"] Thread 2 priority: " +Thread.currentThread().getPriority()); }} }); threadTest1.setPriority(Thread.MAX_PRIORITY); threadTest2.setPriority(Thread.MIN_PRIORITY); threadTest1.start(); threadTest2.start(); } Run thread 1 Run thread 2 [0] Thread 1 priority:10 [0] Thread 2 priority:1 [1] Thread 2 priority:1 [1] Thread 1 priority:10 [2] Thread 1 priority:10 [2] Thread 2 priority:1 [3] Thread 1 priority:10 [4] Thread 1 priority:10 [3] Thread 2 priority:1 [5] Thread 1 priority:10 [6] Thread 1 priority:10 [4] Thread 2 priority:1 [7] Thread 1 priority:10 [8] Thread 1 priority:10 [5] Thread 2 priority:1 [9] Thread 1 priority:10 [6] Thread 2 priority:1 [10] Thread 1 priority:10 [7] Thread 2 priority:1 [11] Thread 1 priority:10 [8] Thread 2 priority:1 …
29
Agenda - Threads Introduction Cycle de vie Créer et manipuler des threads Executors ShutdownHook Gestion des sections critiques Java - Threads & calcul distribué 29
30
Threads - Executors Java - Threads & calcul distribué 30 L'utilisation de la classe Thread étant un peu complexe et sujette aux bugs, il est souvent préférable d'utiliser les API de java.util.concurrent. Elles fournissent un cadre de développement évitant d'utiliser directement les threads : les Executors. Ils permettent l'exécution asynchrone de tâches et de gérer des ThreadPools. L'exemple suivant compare l'exécution d'une tâche en utilisant les Executors avec les threads.
31
Threads - Executors Java - Threads & calcul distribué 31 L'exemple suivant compare l'exécution d'une tâche en utilisant les Executors avec les threads. Thread threadTest1 = new Thread( new Runnable() { @Override public void run() { System.err.println("Run thread 1"); for (int i = 0;i<5;i++) { System.err.println("Loop ["+i+"]"); } } }); threadTest1.start(); ExecutorService executor = Executors.newSingleThreadExecutor(); executor.submit(new Runnable() { @Override public void run() { System.err.println("Run thread 2"); for (int i = 0;i<5;i++) { System.err.println("Loop ["+i+"]"); } } });
32
Threads – Executors ExecutorService Java - Threads & calcul distribué 32 La classe ExecuterService offre les fonctionnalités nécessaires à la soumission de tâches asynchrones. Méthodes de soumissions de tâches: MéthodesDescriptions Future submit(Callable task)Soumet une tâche avec une valeur de retour (Future). Future submit(Runnable task)Soumet une tâche Runnable et renvoi un Future représentant cette tâche Future submit(Runnable task, T result) Soumet une tâche Runnable et renvoi un Future représentant cette tâche.
33
Threads – Executors ExecutorService Java - Threads & calcul distribué 33 Méthodes d’arrêts: MéthodesDescriptions boolean isShutdown()Retourne vrai si l'executor a été arrêté. boolean isTerminated()Retourne vraie si les tâches se sont terminées après un shutdown. void shutdown()Initie un shutdown sur les tâches en cours. Aucune autre tâche ne sera acceptée. List shutdownNow()Essai de stopper tous les threads et retourne la liste des tâches non effectuées. boolean awaitTermination(long timeout, TimeUnit unit) Le programme attend la fin de tous threads après un shutdown ou que le temps alloué pour l'exécution est dépassé ou que le thread courant est interrompu.
34
Threads – Executors ExecutorService Java - Threads & calcul distribué 34 Méthodes de soumissions avec des Collections: MéthodesDescriptions List > invokeAll(Collection > tasks) Exécute l'ensemble des tâches tasks et retourne une liste de Futures où sont stockés les status et les résultat lorsque tous les threads sont terminés. List > invokeAll(Collection > tasks, long timeout, TimeUnit unit) Exécute l'ensemble des tâches tasks et retourne une liste de Futures où sont stockés les status et les résultat lorsque tous les threads sont terminés ou que le temps alloué timeout est dépassé. T invokeAny(Collection > tasks) Exécutes les tâches task et retourne le résultat. T invokeAny(Collection > tasks, long timeout, TimeUnit unit) Exécutes les tâches task et retourne le résultat avant que le temps alloué timeout ne soit dépassé
35
Threads – Executors ExecutorService Java - Threads & calcul distribué 35 Callable & Future: Les threads 'standards' disposent d'une méthode run() n'ayant aucun retour. L'interface Callable permet la définition d'un type de retour. A son exécution (avec la méthode submit), une valeur Future sera retournée. Elle contient le résultat final de de l'exécution de la tâche. Naturellement, tant que la tâche n'est pas terminée l'objet Future ne contient pas de résultat.
36
Threads – Executors ExecutorService Java - Threads & calcul distribué 36 Exemple : Création de 2 threads ExecutorService executor = Executors.newSingleThreadExecutor(); Future mySum1 = executor.submit(new Callable () { @Override public Integer call() { System.err.println("Run thread 1"); int sum = 0; for (int i = 0;i<50;i++) { sum+=i; try { Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace(); } } return new Integer(sum); }}); Future mySum2 = executor.submit(new Callable () { @Override public Integer call() { System.err.println("Run thread 2"); int sum = 0; for (int i = 0;i<30;i++) { sum+=i; try { Thread.sleep(100);} catch (InterruptedException e) { e.printStackTrace(); } } return new Integer(sum); }});
37
Threads – Executors ExecutorService Java - Threads & calcul distribué 37 Exemple : Exécutions des 2 threads long startTime = System.currentTimeMillis(); long currentTime = System.currentTimeMillis(); while(!mySum1.isDone() || !mySum2.isDone()) { currentTime = System.currentTimeMillis(); System.err.println("["+(currentTime-startTime) +"]Active wait result : Th1["+mySum1.isDone() + "] Th2["+mySum2.isDone()+"]"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } try { System.err.println("Thread result:Th1="+mySum1.get()+" Th2="+mySum2.get()); } catch (InterruptedException | ExecutionException e) { } Run thread 1 [0]Active wait result : Th1[false] Th2[false] [1000]Active wait result : Th1[false] Th2[false] [2001]Active wait result : Th1[false] Th2[false] [3001]Active wait result : Th1[false] Th2[false] [4001]Active wait result : Th1[false] Th2[false] [5002]Active wait result : Th1[false] Th2[false] Run thread 2 [6002]Active wait result : Th1[true] Th2[false] [7002]Active wait result : Th1[true] Th2[false] [8003]Active wait result : Th1[true] Th2[false] Thread result:Th1=1225 Th2=435
38
Threads – Executors La classe Executors Java - Threads & calcul distribué 38 La classe Executors contient un ensemble de fonctions statiques pour la création de différents types d' ExecutorServices. Dans l'exemple précédent nous avons utilise la méthode newSingleThreadExecutor(). Cette méthode créée un service permettant l'exécution d'une tâche à la fois : le service maintient donc une liste de tâches qu'il exécute les une à la suite des autres. Ces ExecutorServices peuvent être vus comme une ensemble de Threads dont le code métier et l'exécution est complètement paramétrable, ce sont des ThreadPools (l'exemple précédent présente une ThreadPools à un thread)
39
Threads – Executors La classe Executors Java - Threads & calcul distribué 39 Thread 1 Thread 2 Thread M PoolSize de M threads Tâche N Tâche A Tâche B Tâche C Tâches en attente Tâche en cours Tâches terminées
40
Threads – Executors La classe Executors Java - Threads & calcul distribué 40 MéthodesDescriptions static ExecutorService newCachedThreadPool() Construit une thread pool qui instancie des threads au besoin : si tous les threads traitent une tâche au moment d'une nouvelle soumission de tâche un nouveau thread est instancié, sinon un thread 'non actif' est utilisé. static ExecutorService newFixedThreadPool(int nThreads) Construit une thread pool de taille fixe. static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) Construit une thread pool permettant de planifier les tâches. static ExecutorService newSingleThreadExecutor() Construit une thread pool n'exécutant qu'une tâche à la fois. static ScheduledExecutorService newSingleThreadScheduledExecutor() Construit une thread pool permettant de planifier une tâches à la fois.
41
Agenda - Threads Introduction Cycle de vie Créer et manipuler des threads Executors ShutdownHook Gestion des sections critiques Java - Threads & calcul distribué 41
42
Threads – Executors Shutdown Hook Java - Threads & calcul distribué 42 Un Shutdown hook donne la possibilité d'exécuter des opérations si un programme s'arrête brutalement. public class ShutdownHookExample { public static void main(String[] args) { Thread threadSH = new Thread( new Runnable() { @Override public void run() { System.err.println("Shutdown hook called"); } }); Runtime r=Runtime.getRuntime(); r.addShutdownHook(threadSH); System.out.println("Stop program using crtl-c"); System.out.println("or wait the end to view shutdown hook"); try{Thread.sleep(3000);}catch (Exception e) {} } } Stop program using crtl-c or wait the end to view shutdown hook Shutdown hook called
43
Agenda - Threads Introduction Cycle de vie Créer et manipuler des threads Executors ShutdownHook Gestion des sections critiques Java - Threads & calcul distribué 43
44
Threads – Sections critiques Java - Threads & calcul distribué 44 Les threads partagent le même espace mémoire, ils accèdent donc au même ressources. Les sections critiques, sont les parties du programme que plusieurs threads sont susceptibles d'exécuter au même moment et où les ressources sont mis à jours, supprimées ou encore créées. En java il existe plusieurs stratégies, pour s'assurer qu'une section de code est exécuté par un thread seulement.
45
Threads – Sections critiques synchronized Java - Threads & calcul distribué 45 public static int increment() { count++; return count; } public static void withoutSynchronized() { Future th1 = executor.submit(new Runnable() { @Override public void run() { System.err.println("Start Thread 1.1"); for (int i = 0;i<20000;i++) { ThreadCriticalSection.increment(); } } }); Future th2 = executor.submit(new Runnable() { @Override public void run() { System.err.println("Start Thread 1.2"); for (int i = 0;i<30000;i++) { ThreadCriticalSection.increment(); } } }); try { th1.get(); th2.get(); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } System.err.println("Increment value:"+count+" (should be 50000)"); } Start Thread 1.1 Start Thread 1.2 Increment value:36605 (should be 50000)
46
Threads – Sections critiques synchronized Java - Threads & calcul distribué 46 Dans l'exemple précédent, la méthode increment() ne fait l'objet d'aucune protection de section critique et la ressource count est partagée par tous les threads. Pour incrémenter la valeur de count les étapes suivantes sont effectuées en mémoire et par le processeur: lecture de la valeur courante incrément de la valeur écriture de la nouvelle valeur Lorsque deux(ou plus) threads lisent la valeur simultanément, ils lisent la même valeur et donc incrémentent et écrivent la même valeur. Java propose un moyen s'assurer qu'un seul thread exécute une fonction : nous utiliserons le mot clé synchronized (dans l'exemple précédent la méthode synchronizedIncrement() exécute la même action que la méthode increment() mais est pourvue du mot clé synchronized). La séquence - de lecture - incrément de la valeur - écriture - ne pourra donc être effectuée que par un et uniquement un thread.
47
Threads – Sections critiques synchronized Java - Threads & calcul distribué 47 Java propose un moyen s'assurer qu'un seul thread exécute une fonction : nous utiliserons le mot clé synchronized (dans l'exemple suivant la méthode synchronizedIncrement() exécute la même action que la méthode increment() mais est pourvue du mot clé synchronized). La séquence - de lecture -> incrément de la valeur -> écriture - ne pourra donc être effectuée que par un et uniquement un thread.
48
Threads – Sections critiques synchronized Java - Threads & calcul distribué 48 public static synchronized int synchronizedIncrement(){ count++; return count; } public static void withSynchronized() { Future th1 = executor.submit(new Runnable() { @Override public void run() { System.err.println("Start Thread 2.1"); for (int i = 0;i<20000;i++) { ThreadCriticalSection synchronizedIncrement(); } } }); Future th2 = executor.submit(new Runnable() { @Override public void run() { System.err.println("Start Thread 2.2"); for (int i = 0;i<30000;i++) { ThreadCriticalSection synchronizedIncrement(); } } }); try { th1.get(); th2.get(); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } System.err.println("Increment value:"+count+" (should be 50000)"); } Start Thread 2.1 Start Thread 2.2 Increment value:50000 (should be 50000)
49
Threads – Sections critiques Les blocs synchronized Java - Threads & calcul distribué 49 Il n'est pas toujours nécessaire de synchroniser un fonction entière. Il est possible de ne synchroniser qu'un partie du code, ou qu'un objet particulier. En modifiant l'exemple précédent nous obtenons : public static int synchronizedIncrement() { synchronized(ThreadCriticalSection.class) { synchronizedCount++; } return synchronizedCount; } Ici, la protection d'un bloc est effectuée avec synchronized(ThreadCriticalSection.class). ThreadCriticalSection.class est utilisé car la méthode est statique. Lorsque tel n'est pas le cas nous utiliserons synchronized(this) ou synchronized(o) (avec o l'objet sujet de la section critique).
50
Threads – Sections critiques Les locks Java - Threads & calcul distribué 50 Pour définir une section critique il est possible d'éviter d'utiliser les méthodes ou section synchronized en créant des Locks. Cette fonctionnalité est fournie par l'API Concurrent. L'exemple précédent utilise la classe ReentrantLock elle offre la possibilité de bloquer l'accès une ressources (méthode lock()) par un autre thread. Ici nous avons créé une section critique autour de la variable incrémentée. protected static ReentrantLock myLock =new ReentrantLock() ; […] public static int lockIncrement() { myLock.lock(); synchronizedCount++; myLock.unlock(); return synchronizedCount; } […]
51
Threads – Sections critiques Les deadlocks Java - Threads & calcul distribué 51 Les Dead locks arrivent lorsque deux threads se bloquent entre eux. public class DeadLock { static class PingPong { private final String status; public PingPong(String status) { this.status = status; } public String getStatus() { return this.status; } public synchronized void ping(PingPong pingORpong) { System.out.format(Thread.currentThread().getName() + " | %s -> %s\n", this.status, pingORpong.getStatus()); pingORpong.pong(this); } public synchronized void pong(PingPong pingORpong) { System.out.format(Thread.currentThread().getName() +" | %s: %s\n", this.status, pingORpong.getStatus()); }
52
Threads – Sections critiques Les deadlocks Java - Threads & calcul distribué 52 public static void main(String[] args) { final PingPong ping = new PingPong("ping"); final PingPong pong = new PingPong("pong"); new Thread(new Runnable() { public void run() { System.err.println("Ping do 'pong'"); ping.ping(pong); System.err.println("End ping->pong'"); } }).start(); new Thread(new Runnable() { public void run() { System.err.println("Pong do 'ping'"); pong.ping(ping); System.err.println("End pong->ping'"); } }).start(); } } Ping do 'pong' Pong do 'ping' Thread-0 | ping -> pong Thread-1 | pong -> ping Le programme ne s'arrête pas ! Schéma d'exécution de l'exemple thread 0 la ressource ping appelle la méthode ping() : ping bloqué thread 1 la ressource pong appelle la méthode ping() : pong bloqué thread 0 la ressource ping veut utiliser la ressource pong qui est bloquée : ping attend thread 1 la ressource pong veut utiliser la ressource ping qui est bloquée : pong attend
53
Agenda – Calcul distribué Introduction Création de la partie server Création de la partie client Java - Threads & calcul distribué 53
54
Calcul distribué Introduction Java - Threads & calcul distribué 54 L'API RMI de Java fournie les méthodes pour manipuler des objets distants (c'est à dire au travers d'un lien réseau) de manière transparente.
55
Calcul distribué Introduction Java - Threads & calcul distribué 55 Client Server RMI Registry Programme Server STUB Code métier Server SKELETON Communication Recherche un objet Renvoi un Server STUB S’enregistre
56
Calcul distribué Introduction Java - Threads & calcul distribué 56 Pour utiliser cette architecture, les différentes étapes à mettre en œuvre sont les suivantes : Côté server Exécuter rmiregistry auprès duquel le server s'enregistrera Exécuter la partie 'server' Côté client Localiser le server grâce au registre RMI et obtenir une le Stub (image de l'interface métier du server) Lancer les méthodes
57
Agenda – Calcul distribué Introduction Création de la partie server Création de la partie client Java - Threads & calcul distribué 57
58
Calcul distribué Partie server Java - Threads & calcul distribué 58 package edu.iut; import java.rmi.Remote; import java.rmi.RemoteException; public interface IMathOperations extends Remote { public double add(double a,double b) throws RemoteException; public double minus(double a,double b) throws RemoteException; public double time(double a, double b) throws RemoteException; public double divide(double a, double b) throws RemoteException; } Interface contenant la description des opérations package edu.iut; import java.rmi.RemoteException; import java.rmi.server.RMIClientSocketFactory; import java.rmi.server.RMIServerSocketFactory; import java.rmi.server.UnicastRemoteObject; public class MathOperations extends UnicastRemoteObject implements IMathOperations { […] @Override public double add(double a, double b) throws RemoteException { return a+b; } @Override public double minus(double a, double b) throws RemoteException { return a-b; } […] Code métier
59
Calcul distribué Partie server Java - Threads & calcul distribué 59 package edu.iut; import java.rmi.Naming; public class MathOperationsServer { public static void main(String[] args) { try { System.setSecurityManager(new SecurityManager()); MathOperations mathops = new MathOperations(); Naming.rebind("rmi://localhost/MathOperations", mathops); System.out.println("MathOperations Server is ready."); }catch (Exception e) { System.out.println("MathOperations Server failed to start: " + e); }
60
Calcul distribué Partie server Java - Threads & calcul distribué 60 Pour créer les interfaces de communication Stub (côté client) et Skeleton (côté server) il est nécessaire d'utiliser un outil disponible en ligne de commande : rmic. Il suffit donc d'ouvrir un console, de se placer dans le dossier bin de votre projet et de taper: rmic edu.iut.MathOperations Il faut ensuite exécuter le registre RMI avec l'outil rmiregistry : il faut simplement ouvrir une console et taper rmiregistry Ensuite nous devons créer un fichier pour lever les politiques de sécurité. Dans l'exemple nous avons créé un dossier rmipolicy à la racine du projet. Dans ce dossier nous avons écrit un fichier security.policy contenant grant { permission java.security.AllPermission; }; Pour finir, nous configurons l'exécution du projet : java rmi server arguments Il ne reste plus qu'à exécuter le server.
61
Calcul distribué Partie server Java - Threads & calcul distribué 61 Pour finir, nous configurons l'exécution du projet : Il ne reste plus qu'à exécuter le server.
62
Agenda – Calcul distribué Introduction Création de la partie server Création de la partie client Java - Threads & calcul distribué 62
63
Calcul distribué Partie client Java - Threads & calcul distribué 63 package edu.iut; import java.rmi.Naming; public class MathOperationsClient { public static void main(String[] args) { IMathOperations mathops = null; try { System.setSecurityManager(new SecurityManager()); mathops = (IMathOperations)Naming.lookup("rmi://localhost/MathOperations"); System.out.println(mathops.add(3,5)+" | " + mathops.time(3, 5)+" | " + mathops.minus(3, 5)+" | " + mathops.divide(3, 5)+" | "); } catch (Exception e) { System.out.println("MathOperationsClient exception: " + e); }
64
Calcul distribué Partie client Java - Threads & calcul distribué 64 Avant d'exécuter le client, il est nécessaire de copier le fichier de politiques de sécurité ainsi que le fichier _Stub.class, se trouvant dans le dossier bin/edu/iut du projet du server dans le dossier bin/edu/iut du projet du client. Il est également nécessaire de copier le IMathOperations.java dans le package du client (edu.iut). Il ne reste plus qu'à exécuter le client. Les configurations des politiques de sécurité (avec le fichier security.policy) et les options de la JVM sont identiques à celle de la partie server.
Présentations similaires
© 2024 SlidePlayer.fr Inc.
All rights reserved.