Le blog de Fabien DUMINY

Un blog utilisant WordPress

Skip to: Content | Sidebar | Footer

Devoxx France 2012 – Deadlock Victim

30 avril, 2012 (09:00) | Devoxx France 2012, Evènement, Java | By: fabien

Lors de la conférence intitulée Deadlock Victim faite à Devoxx France 2012, Heinz Kabutz et Olivier Croisier ont parlé du sujet des DeadLock.

En prenant le problème du dîner des philosophes comme exemple, ils nous montrent qu’une stratégie inappropriée peut conduire à un DeadLock. Dans le cas d’une base de données, le moteur choisit la victime du DeadLock en retournant une exception SQL à l’un des clients impliqués. Par contre, dans le cas d’un programme Java faisant intervenir au minimum 2 threads qui veulent chacun accéder à 2 ressources (après les avoir verrouillées), il n’y a aucune exception pour indiquer qu’un thread est impliqué dans un DeadLock (dans ce cas, il serait bien qu’une Error soit lancée par le thread).

La solution à ce problème (appelé Left-Right DeadLock) consiste à appliquer la stratégie suivante pour tous les philosophes :

  1. prendre (verrouiller) le couvert à sa droite
  2. prendre (verrouiller) le couvert à sa gauche
  3. poser (déverrouiller) le couvert à sa gauche
  4. poser (déverrouiller) le couvert à sa droite

Remarques :

  • Il est bien sûr possible de prendre la stratégie opposée : le couvert de gauche, puis celui de droite. L’essentiel est que tous les philosophes appliquent la même stratégie.
  • Il est important qu’un philosophe pose ses couverts dans l’ordre inverse où il les a pris

Au lieu d’utiliser la notion droite-gauche, il est possible de numéroter chacun des couverts avec un numéro unique. Dans ce cas, il y a 2 stratégies possibles : prendre d’abord le couvert avec le plus petit numéro (parmi les 2 situés près d’un philosophe), prendre d’abord celui avec le plus grand numéro. Encore une fois, l’important est que les philosophes appliquent tous la même stratégie. Cela permet de trouver une solution générique à tous les problèmes de DeadLock : il faut définir un ordre strict parmi les ressources (en leur associant par exemple un identifiant numérique unique) et appliquer la stratégie du « plus petit d’abord ».

Parmi les cas concrets, il y a celui de la méthode privée writeObject(ObjectOutputStream) de la classe Vector, synchronisée sur l’instance. Un DeadLock risque de se produire lors de la sérialisation de 2 vecteurs contenant chacun une référence sur l’autre.

Pour la partie test unitaire, comment vérifier que le DeadLock est corrigé ? Combien de fois faut-il faire le test pour prouver que la correction est efficace ? En effet, un DeadLock peut se produire de temps en temps et pas forcément systématiquement. Un bon test doit passer ou ne pas passer, indépendamment des conditions extérieures (charge du processeur …). Heinz et Olivier proposent de rajouter une méthode vide nommée sleep dans le code en production et de l’appeler entre les 2 tentatives de verrouillage de 2 ressources différentes. En surchargeant la méthode sleep dans le code des tests pour appeler Thread.sleep(long), il devient possible de révéler la présence ou l’absence de DeadLock de manière déterministe.

Depuis Java 6, il existe de nouvelles fonctionnalités permettant de faciliter la détection et la correction d’un DeadLock :

  • Visualiser l’état des threads d’une JVM en fonctionnement :
    • Sous Windows : Il faut que la JVM ait été lancée dans une console et taper Ctrl-Break
    • Sous Linux : Si la JVM a été lancée dans une console, taper Ctrl-\. Sinon, envoyer le signal QUIT au processus avec la commande kill -QUIT process_id, où process_id est l’identifiant du processus (que l’on peut retrouver avec la commande ps axf | grep java)

    Ensuite, il faut utiliser la commande jstack process_id.

  • Lister les threads impliqués dans un DeadLock en utilisant JMX. Cela ne fonctionne que pour les locks du même type que celui utilisé par ReentrantLock et pas pour les locks utilisant un moniteur (mot clé synchronized).

Pour illustrer cela, Heinz et Olivier ont créé une classe appelée DeadlockArbitrator qui tue un thread au hasard parmi ceux qui sont impliqués dans un DeadLock (dont la liste est obtenue par JMX). Ensuite, ils font la démonstration d’une application Swing avec un bouton pour provoquer un DeadLock et un autre pour tuer un thread provoquant un DeadLock (en utilisant la classe DeadlockArbitrator).
Remarque : pour tuer un thread, la classe DeadlockArbitrator utilise la méthode dépréciée (mais bien utile dans ce cas) Thread.stop(Throwable). Il ne faut utiliser cette technique que pour du code que l’on ne peut pas corriger (librairies tierces). Dans les autres cas, il faut évidemment corriger le DeadLock.

Pour plus d’informations sur des sujets techniques comme celui-ci, Heinz nous invite à consulter son site Javaspecialists.eu

Be Sociable, Share!
Share and Enjoy

Write a comment





If your website is claim enabled, it will be notified that you have posted here.

MySQL query error