alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Akka/Scala example source code file (DiningHakkersOnBecome.java)

This example Akka source code file (DiningHakkersOnBecome.java) is included in my "Source Code Warehouse" project. The intent of this project is to help you more easily find Akka and Scala source code examples by using tags.

All credit for the original source code belongs to akka.io; I'm just trying to make examples easier to find. (For my Scala work, see my Scala examples and tutorials.)

Akka tags/keywords

abstractactor, actor, actorref, akka, boxedunit, chopstick, concurrent, duration, hakker, milliseconds, partialfunction, put, receivebuilder, runtime, seconds, time

The DiningHakkersOnBecome.java Akka example source code

package sample.become;

import akka.actor.*;
import akka.japi.pf.ReceiveBuilder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import scala.concurrent.duration.Duration;
import scala.concurrent.duration.FiniteDuration;
import scala.PartialFunction;
import scala.runtime.BoxedUnit;

import static sample.become.Messages.*;
import static java.util.concurrent.TimeUnit.*;

// Akka adaptation of
// http://www.dalnefre.com/wp/2010/08/dining-philosophers-in-humus/

public class DiningHakkersOnBecome {

  /*
   * A Chopstick is an actor, it can be taken, and put back
   */
  public static class Chopstick extends AbstractActor {

    //When a Chopstick is taken by a hakker
    //It will refuse to be taken by other hakkers
    //But the owning hakker can put it back
    PartialFunction<Object, BoxedUnit> takenBy(ActorRef hakker) {
      return ReceiveBuilder.
        match(Take.class,
          t -> t.hakker.tell(new Busy(self()), self())).
        match(Put.class, p -> p.hakker == hakker,
          p -> context().become(available)).
        build();
    }

    //When a Chopstick is available, it can be taken by a hakker
    PartialFunction<Object, BoxedUnit> available = ReceiveBuilder.
      match(Take.class, t -> {
        context().become(takenBy(t.hakker));
        t.hakker.tell(new Taken(self()), self());
      }).build();

    //A Chopstick begins its existence as available
    public Chopstick() {
      receive(available);
    }
  }

  /*
   * A hakker is an awesome dude or dudette who either thinks about hacking or has to eat ;-)
   */
   public static class Hakker extends AbstractActor {
    private String name;
    private ActorRef left;
    private ActorRef right;

    public Hakker(String name, ActorRef left, ActorRef right) {
      this.name = name;
      this.left = left;
      this.right = right;
    }

    //When a hakker is eating, he can decide to start to think,
    //then he puts down his chopsticks and starts to think
    PartialFunction<Object, BoxedUnit> eating = ReceiveBuilder.
      matchEquals(Think, m -> {
        left.tell(new Put(self()), self());
        right.tell(new Put(self()), self());
        System.out.println(String.format("%s puts down his chopsticks and starts to think", name));
        startThinking(Duration.create(5, SECONDS));
      }).build();

    //When a hakker is waiting for the last chopstick it can either obtain it
    //and start eating, or the other chopstick was busy, and the hakker goes
    //back to think about how he should obtain his chopsticks :-)
    PartialFunction<Object, BoxedUnit> waitingFor(ActorRef chopstickToWaitFor, ActorRef otherChopstick) {
      return ReceiveBuilder.
        match(Taken.class, t -> t.chopstick == chopstickToWaitFor, t -> {
          System.out.println(String.format("%s has picked up %s and %s and starts to eat",
            name, left.path().name(), right.path().name()));
          context().become(eating);
          context().system().scheduler().scheduleOnce(Duration.create(5, SECONDS), self(), Think, context().system().dispatcher(), self());
        }).
        match(Busy.class, b -> {
          otherChopstick.tell(new Put(self()), self());
          startThinking(Duration.create(10, MILLISECONDS));
        }).
        build();
    }

    //When the results of the other grab comes back,
    //he needs to put it back if he got the other one.
    //Then go back and think and try to grab the chopsticks again
    PartialFunction<Object, BoxedUnit> deniedAChopstick = ReceiveBuilder.
      match(Taken.class, t -> {
        t.chopstick.tell(new Put(self()), self());
        startThinking(Duration.create(10, MILLISECONDS));
      }).
      match(Busy.class, b ->
        startThinking(Duration.create(10, MILLISECONDS))).
      build();

    //When a hakker is hungry it tries to pick up its chopsticks and eat
    //When it picks one up, it goes into wait for the other
    //If the hakkers first attempt at grabbing a chopstick fails,
    //it starts to wait for the response of the other grab
    PartialFunction<Object, BoxedUnit> hungry = ReceiveBuilder.
      match(Taken.class, t -> t.chopstick == left,
        t -> context().become(waitingFor(right, left))).
      match(Taken.class, t -> t.chopstick == right,
        t -> context().become(waitingFor(left, right))).
      match(Busy.class,
        b -> context().become(deniedAChopstick)).
      build();

    //When a hakker is thinking it can become hungry
    //and try to pick up its chopsticks and eat
    PartialFunction<Object, BoxedUnit> thinking = ReceiveBuilder.
      matchEquals(Eat, m -> {
        context().become(hungry);
        left.tell(new Take(self()), self());
        right.tell(new Take(self()), self());
      }).build();

    //All hakkers start in a non-eating state
    public Hakker() {
      receive(ReceiveBuilder.matchEquals(Think, m -> {
        System.out.println(String.format("%s starts to think", name));
        startThinking(Duration.create(5, SECONDS));
      }).build());
    }

    private void startThinking(FiniteDuration duration) {
      context().become(thinking);
      context().system().scheduler().scheduleOnce(duration, self(), Eat, context().system().dispatcher(), self());
    }
  }

  /*
  * Alright, here's our test-harness
  */
  public static void main(String[] args) {
    ActorSystem system = ActorSystem.create();
    //Create 5 chopsticks
    ActorRef[] chopsticks = new ActorRef[5];
    for (int i = 0; i < 5; i++)
      chopsticks[i] = system.actorOf(Props.create(Chopstick.class), "Chopstick" + i);

    //Create 5 awesome hakkers and assign them their left and right chopstick
    List<String> names = Arrays.asList("Ghosh", "Boner", "Klang", "Krasser", "Manie");
    List<ActorRef> hakkers = new ArrayList<>();
    int i = 0;
    for (String name: names) {
      hakkers.add(system.actorOf(Props.create(Hakker.class, name, chopsticks[i], chopsticks[(i + 1) % 5])));
      i++;
    }
    //Signal all hakkers that they should start thinking, and watch the show
    hakkers.stream().forEach(hakker -> hakker.tell(Think, ActorRef.noSender()));
  }
}

Other Akka source code examples

Here is a short list of links related to this Akka DiningHakkersOnBecome.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.