:: Enseignements :: Master :: M1 :: 2014-2015 :: Java Avancé ::
[LOGO]

Volatile, Atomic, Compare and Set


Exercice 1 - A vos chronometres

On cherche à savoir combien on peut faire d'itération d'une boucle en 100 millisecondes, un de vos collègues a produit le code suivant:

  1. Sans exécuter le code, que fait ce programme ?
  2. Vérifier en exécutant le programme si vous avez vu juste.
  3. Comment doit on corriger le problème ?
    Modifier la classe Bogus en conséquence.
  4. On cherche maintenant a accelérer le code de bogus et en utilisant le mot clé volatile au lieu des blocs synchronized.
    Créer une classe BogusVolatile qui n'utilise pas de block synchronized.
    Comment appele t'on les implantations qui n'ont ni block synchronized ni lock ?

Exercice 2 - Generateur pseudo-aléatoire lock-free

On souhaite modifier la classe RandomNumberGenerator pour la rendre thread-safe sans utiliser ni section critique ni verrou (lock free donc).

  1. Expliquer comment fonctionne un générateur pseudo-aléatoire et pourquoi l'implantation ci-dessus n'est pas thread-safe.
  2. Utiliser la classe AtomicLong et la méthode compareAndSet pour obtenir une implantation lock-free du générateur pseudo aléatoire.
  3. Un des inconvénients des champs "atomiques" est qu'ils allourdissent l'allocation nécessaire pour chaque objet. En effet, pour utiliser un long pour chaque objet générateur, il faut alloouer pour chacun des objets un AtomicLong qui permettra lui-même d'accéder de manière atomique à la valeur d'un long, chaque accès nécessitant lui-même une indirection...
    Faites une nouvelle implémentation du générateur pseudo aléatoire qui utilise un AtomicLongFieldUpdater de la classe AtomicLongFieldUpdater qui ne nécessite qu'une seule instance (static) pour mettre à jour de manière atomique le champ volatile long de n'importe lequel des objets générateur de cette classe.
  4. Depuis le jdk 1.8, vos deux classes précédentes peuvent utiliser la méthode updateAndGet sur AtomicLong comme sur AtomicLongFieldUpdater. Modifiez votre code en conséquence.

Exercice 3 - Liste concurrente et atomicité

On souhaite écrire une implantation de liste chaînée de chaînes de caractères avec insertion à la fin, concurrente et n'utilisant ni section critique, ni verrou.
La liste devra possèder deux méthodes addLast(E e) et forEach() permettant respectivement d'ajouter un élement en fin de la liste et d'appeler un java.util.function.Consumer sur l'ensemble des élements de la liste.
Le code ci-dessous est une implantation non-thread safe de la liste

Détail d'implantation, pour éviter de gérer différemment le cas de la liste vide, une liste est crée initialement avec un maillon contenant la valeur null.

L'idée de l'algorithme concurrent est la suivante: pour éviter toute synchronisation lors de l'ajout, on récupere le maillon à la fin de la liste puis on teste en utilisant une opération atomique si le maillon est toujours la fin de la liste; si oui, on lui assigner le nouveau maillon créé. Si ce n'est pas le dernier maillon, on récupère de nouveau le maillon à la fin de la liste et on recommence la même opération...

  1. Recopier le code de la classe StringList dans une classe LockFreeStringList qui va implanter une liste threadsafe sans verrou.
    Dans un premier temps, implanter la méthode addLast en utilisant la classe AtomicReferenceFieldUpdater.
    Comment doit-on modifier le code de forEach pour que la méthode soit thread-safe ?
  2. On souhaite améliorer la complexité de la méthode addLast en maintenant, en plus d'une référence sur la tête de la liste (head), une référence sur la queue de la liste (tail).
    Modifier l'implantation de addLast pour utiliser le champ tail et le mettre à jour.