:: Enseignements :: ESIPE :: E4INFO :: 2019-2020 :: Java Inside ::
[LOGO]

Continuation


Continuation, Concurrence coopérative

Exercice 1 - Continuation

Le but de cet exercice est se familiariser avec la notion de Continuation.

  1. Dans le répertoire java-inside, utiliser Maven pour générer les fichiers pour le lab6
          mvn archetype:generate \
            -DarchetypeArtifactId=maven-archetype-quickstart \
            -DgroupId=fr.umlv.java.inside \
            -DartifactId=lab6  \
            -DinteractiveMode=false
        

    Recopier les properties, dependencies et les plugins de build du pom.xml des labs précédents pour être capable d'exécuter les tests Junit.
    Attention contrairement aux TPs précédents, nous allons utilisé une version béta du JDK du projet Loom de l'OpenJDK.
    Pour cela, nous utiliserons le JDK ici: /home/ens/forax/java-inside/jdk-14-loom
    Pour ceux qui sont sur leur portable, ce JDK est téléchargable
    Pour linux: jdk-14-loom-linux.tar.gz
    Pour macOS: jdk-14-loom-osx.tar.gz
  2. Créer un projet Maven dans Eclipse/IntelliJ pointant sur le répertoire lab6 et faite en sorte que le JDK utiliser pour ce projet pointe sur jdk-14-loom.
  3. Dans votre IDE, créer une classe Example1 avec un main qui créé une continuation qui affiche "hello continuation", ayant pour scope "hello1" puis appel la méthode run sur la continuation.
  4. Ajouter un appel à Continuation.yield() avant l'affichage de "hello continuation".
    Que se passe-t'il ?
    Appeler une seconde fois la méthode run sur la continuation dans le main, Que se passe-t'il ?
  5. A votre avis comment fonctionne une continuation lorsque l'on appel Continuation.yield() et lorsque l'on appel run().
  6. Que se passe-t'il si on appel run() deux fois et qu'il n'y a pas d'appel à Continuation.yield() à l'intérieur du code de la continuation ?
    Est-ce le comportement que l'on attend ?
  7. Modifier le fichier .travis.yml pour que Travis test aussi le lab6.
  8. Quel est le comportement de l'appel Continuation.getCurrentContinuation(scope) lorsqu'on l'appel à l'intérieur du code de la continuation ou dans le main ?
    Comparer le comportement de Thread.currentThread() pour une Thread par rapport à Continuation.getCurrentContinuation pour une Continuation.
  9. Que se passe t'il lorsque l'on met un bloc synchronized autour d'un appel à Continuation.yield() ?
    Essayer d'expliquer ce comportement ?
  10. Il existe une méthode d'instance isDone sur une Continuation qui permet de savoir si le code d'une continuation a été complètement exécuter ou pas.
    On souhaite s'en servir pour exécuter le code de plusieurs continuations indépendamment du nombre d'appel à Continuation.yield à l'intérieur du code de ces continuations.
          var scope = new ContinuationScope("scope");
          var continuation1 = new Continuation(scope, () -> {
            System.out.println("start 1");
            Continuation.yield(scope);
            System.out.println("middle 1");
            Continuation.yield(scope);
            System.out.println("end 1");
          });
          var continuation2 = new Continuation(scope, () -> {
            System.out.println("start 2");
            Continuation.yield(scope);
            System.out.println("middle 2");
            Continuation.yield(scope);
            System.out.println("end 2");
          });
          var list = List.of(continuation1, continuation2);
          ...
        
    Finir le code pour que les deux continuations s'exécute alternativement.
  11. Qu'elle est la différence entre une Thread et une Continuation ?
  12. Créer une classe Scheduler
    • qui possède une méthode enqueue qui enregistre la continuation courante dans le Scheduler et fait un Continuation.yield().
      ou lève un beau message d'erreur si il n'y a pas de continuation courante.
    • qui possède une méthode runLoop qui en boucle, décide parmis les continuation enregistrées (les continuations en attente) quelle va être la prochaine continuation à exécuter et exécute celle-ci et s'arrête si il n'y a plus de continuation à exécuter.
    Pour l'instant on va dire que lorsque l'on doit choisir parmis plusieurs continuations, on prend la dernière qui s'est enregistrée.
    Voilà un exemple d'utilisation
          var scope = new ContinuationScope("scope");
          var scheduler = new Scheduler();
          var continuation1 = new Continuation(scope, () -> {
            System.out.println("start 1");
            scheduler.enqueue(scope);
            System.out.println("middle 1");
            scheduler.enqueue(scope);
            System.out.println("end 1");
          });
          var continuation2 = new Continuation(scope, () -> {
            System.out.println("start 2");
            scheduler.enqueue(scope);
            System.out.println("middle 2");
            scheduler.enqueue(scope);
            System.out.println("end 2");
          });
          var list = List.of(continuation1, continuation2);
          list.forEach(Continuation::run);
          scheduler.runLoop();
        
  13. Modifier le scheduler pour qu'il prenne une politique d'exécution à la construction parmis:
    • STACK qui exécute la dernière continuation qui s'est enregistrée,
    • FIFO qui exécute la première continuation qui s'est enregistrée,
    • RANDOM qui exécute une continuation au hazard (Il existe une classe java.util.concurrent.ThreadLocalRandom).
  14. Ecrire les tests JUnit testant les différents politiques d'exécution et faite en sorte que Travis exécute les tests.