:: Enseignements :: ESIPE :: E4INFO :: 2015-2016 :: Java Réseau I - Concurrence et E/S ::
[LOGO]

Examen de concurrence sur table - Session de Juillet


Vous avez droit à aucun document.

Exercice 1 - Questions de cours (7)

Répondez aux questions suivantes en deux ou trois phrases, pas plus, et SVP répondez à la question pas au mot-clef.

  1. Qu'est ce qu'une classe thread-safe ?
  2. A quoi servent les classes du package java.util.concurrent.atomic. Quelles sont les avantages/inconvénients par rapport à l'utilisation de moniteur avec le bloc synchronized.
  3. Le code suivant a t'il un problème de publication ?
         public class Point {
           private volatile int x;
           private long y;
           
           public Point(int x, long y) {
             this.x = x;
             this.y = y;
           }
         }
        
    Si oui, pourquoi ? si non pourquoi ?
  4. Pourquoi un notify sur un objet doit être appelé dans un bloc synchronized sur le même objet. Quelle serait le ou les problèmes si Java n'imposait pas cette restriction.
  5. Quelles sont les deux raisons pour lesquels il faut mettre les appels à wait à l'intérieur d'une boucle while.
  6. Quel est l'intérêt d'utiliser un pool de threads (on parle d'executor en Java) par rapport à gérer des threads à la main ?
  7. A quoi sert l'interface java.util.concurrent.Future.

Exercice 2 - Flux (7)

La classe Flux permet de connecter un ensemble de puits (sink en anglais) de données à un ensemble de sources de données. Un puit de données consomme des valeurs alors qu'une source de données produit des données.
La méthode sink permet d'enregistrer un puit de donnée, une méthode (une lambda) qui sera exécutée à chaque fois qu'une donnée est produite.
La méthode source permet de définir une source de donnée, les données sont envoyées en appelant autant de fois que nécessaire la méthode accept sur l'accepteur (acceptor) pris en paramètre. Les données commence à être envoyée dès l'appel de la méthode source.

public class Flux<T> {
  private final ArrayList<Consumer<? super T>> consumers = new ArrayList<>();
  
  public void sink(Consumer<? super T> consumer) {
    consumers.add(consumer);
  }
  
  public void source(Consumer<Consumer<? super T>> acceptorConsumer) {
    acceptorConsumer.accept(t -> {
      for(Consumer<? super T> consumer: consumers) {
        consumer.accept(t);
      }
    });
  }
}
  
Voici un exemple de main de test qui affiche les valeurs de 0 à 9 à la fois sur l'entré standard et sur la sortie standard.

  public static void main(String[] args) {
    Flux<Integer> flux = new Flux<>();
    flux.sink(System.out::println);
    flux.sink(System.err::println);
    flux.source(acceptor -> {
      for(int i= 0; i < 10; i++) {
        acceptor.accept(i);
      }
    });
  }  
  
  1. Indiquer le code d'un main qui créé une thread pour envoyer les valeurs de 0 à 9 à travers l'accepteur.
  2. Pourquoi le code que vous avez écrit ne va pas fonctionner comme il devrait ?
    Quel est le problème ?
  3. En fait, si l'on veut que la classe Flux soit thread safe (et ce pour n'importe quel main), il faut aussi régler le problème qui arrive lorsque l'on utilise un seul puit avec deux sources différentes.
    Quel est le problème ?
  4. Indiquer un nouveau code pour la classe Flux qui rend la classe Flux thread safe (c'est à dire qui rêgles les deux problèmes vu dans les deux questions précédentes) en utilisant la syntaxe synchronized.
  5. Indiquer un nouveau code pour la classe Flux qui la rend thread safe mais cette fois en utilisant les ReentrantLock
  6. Enfin, ici, il est possible d'avoir un code beaucoup plus efficace en utilisant les collections concurrentes du package java.util.concurrent, que doit on modifier dans la classe Flux dans ce cas et pourquoi ?

Exercice 3 - PermitPool (6)

On souhaite implanter une classe stockant un nombre de permis définie lors de la création de l'objet et permettant à des threads d'attraper (grab) plusieurs permis puis de relacher (ungrab) le même nombre de permis. Dans le cas ou un thread chercherait à prendre plus de permis que ce qui est disponible, celle-ci sera mis en attente.

public class PermitPool {
  /**
   * Create a PermitPool with a maximum number of permits.
   * @param maxPermits the maximum number of permits allowed to be grabbed by one thread
   *   if all other thread have not grab any permits.
   */
  public PermitPool(int maxPermits) {
    
  }
  
  /**
   * Try to grab some permits.
   * This method may block if there is not enough permits in the permit pool
   * @param permits number of permits to grab.
   * @throws IllegalArgumentException if the number of permits is negative or zero
   *   or bigger than max permits.
   * @throws IllegalStateException if the current thread has already grab some permits
   *   without releasing them with ungrab.
   * @throws InterruptedException if the thread is interrupted
   *   while waiting to grab the permits.
   */
  public void grab(int permits) throws InterruptedException {
    
  }
  
  /**
   * Release the number of permits previously taken by grab.
   * @throws IllegalStateException if the current thread doesn't hold any permits
       (i.e. have not grab any permits before).
   */
  public void ungrab() {
    
  }
}
  
  1. Donner le code la classe PermitPool.