Problèmes du multi-threading

Deadlock, starvation et livelock

Ce site ne sera plus alimenté de contenu après août 2014. Tous les nouveaux articles seront redigés pour www.waitingforcode.com

Synchronisation est un processus nécessaire pour garantir une cohérence des données dans une application multi threading. Sa mauvaise implémentation peut causer, dans les meilleurs des cas, l'incohérence des informations. Dans les pires des cas, l'application peut même être bloquée. Dans cet article on verra quels problèmes peuvent se produire suite à des erreurs de programmation dans l'environnement multi threading.

Problèmes du multi-threading en Java

Cependant malgré ces moyens de développement, chaque application multi-threading est très fragile. Elle peut être confrontée à des problèmes du type deadlock, starvation ou livelock. Regardons à quoi ils ressemblent :

- deadlock : correspond à la situation où plusieurs Threads sont bloqués car ils attendent la réaction d'autres Threads. Cependant, cette réaction est impossible car ils sont également bloqués (en attente de réaction de la tâche bloquée).

On utilisera la situation où deux personnes veulent faire un sandwich avec du radis et du fromage. La première personne prend d'abord un peu de fromage et attend que l'autre termine avec du radis. La deuxième personne fait l'inverse. Cependant, le découpage d'ingrédients prend du temps et aucun des deux n'arrive pas à débloquer la situation. Voici le code :

afficher le code

Après l'exécution on verra sur l'écran :

T2 has taken radish
T1 has taken cheese

starvation : apparaît quand un Thread n'arrive pas à terminer sa tâche liée à une ressource partagée avec d'autres Threads. Ce blocage peut être le résultat d'un blocage d'accès à cette ressource par d'autres Threads.

Imaginons la situation suivante : on espionne plusieurs sites web. Chaque jour on lance plusieurs tâches qui tentent de récupérer (StarvationTask) les informations intéressantes. L'application admet le lancement des 2 tâches simultanées. Voici le code qui illustre cette problématique :

afficher le code

Sur l'écran on verra :

Calling Task 0 #1
Calling Task 2 #1
Calling Task 3 #1
Calling Task 1 #1
Calling Task 5 #1
Calling Task 6 #1
Calling Task 7 #1
Got Calling Task 0 #1
Got Calling Task 1 #1
Got Calling Task 2 #1
Got Calling Task 3 #1

Au titre de comparaison, voici le résultat correct, quand sourceAvailable() retourne true :

afficher le code

Le problème repose dans la méthode sourceAvailable() qui retourne toujours false et ainsi bloque l'exécution des Threads suivants. Les deux (tâches dont les noms contiennent 4 et 8) prennent toutes les ressources disponibles et occupent la queue infiniment. Bien sûr, la situation est extrême (valeur retournée est fixe), mais personne ne peut garantir que deux sites analysés seront toujours disponibles (par exemple que leur serveur DNS ne tombera pas en panne au même moment).

- livelock : ressemble au deadlock car apparaît quand les Threads n'arrivent pas à avancer et sont dépendants l'un de l'autre. Contrairement à la première situation évoquée, ces tâches ne sont pas bloquées. Elles sont seulement trop occupées pour répondre et permettre à l'autre d'avancer. Il se peut également que tous les Threads soient bloqués. Ils seraient donc en impossibilité de débloquer l'objet vérouillé.

Revenons à notre situation avec la queue chez un médecin. Elle ressemble beaucoup à la dernière situation où les Threads n'arrivent pas à reprendre l'exécution du programme. Sans l'appel de la méthode notify(), l'exécution des Threads s'arrête. En fait les tâches en attente ne sont pas notifiées que le statut principal a changé en leur permettant d'aborder l'action suivante. Voici le code incorrect qui parfois peut provoquer le problème livelock :

afficher le code

On constate qu'il est incorrect à cause de résultats comme celui-ci :

Run Patient F1
Run Patient F2
Patient F1 is checking if he can enter.
Patient F1 has entered.
Patient F2 is checking if he can enter.
Patient F2 can't enter. He is waiting his turn.

Patient F1 is going to home.

Run Patient F3
Patient F3 is checking if he can enter.
Patient F3 has entered.

Patient F3 is going to home.
Bartosz KONIECZNY Concurrence

Une question ? Une remarque ?

*

*

Moi

Développeur d'applications Internet et journaliste passionné par l'adjectif français. Un aigle polonais orienté vers la progression, volant très haut et écoutant du zouk après les matches du foot français.

Vous appréciez mon travail ?

Pour contribuer au développement de ce site, ou pour remercier pour des articles rédigés, vous pouvez faire un don.

Un conseil Android

Afficher les logs sous Android.

Les logs d'Android s'avèrent très utiles lors du développement de notre application. La commande suivante permet de les afficher rapidement (exemple issu du Cygwin) : cd /cygdrive/c/Program\ Files\ \(x86\)/Android/android-sdk/platform-tools/ ./adb.exe logcat