|
Akka/Scala example source code file (DiningHakkersOnFsm.java)
The DiningHakkersOnFsm.java Akka example source codepackage sample.fsm; import akka.actor.*; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import scala.concurrent.duration.Duration; import scala.concurrent.duration.FiniteDuration; import static java.util.concurrent.TimeUnit.*; import static sample.fsm.Messages.*; // Akka adaptation of // http://www.dalnefre.com/wp/2010/08/dining-philosophers-in-humus/ public class DiningHakkersOnFsm { /** * Some states the chopstick can be in */ public static enum CS { Available, Taken } /** * Some state container for the chopstick */ public static final class TakenBy { public final ActorRef hakker; public TakenBy(ActorRef hakker){ this.hakker = hakker; } } /* * A chopstick is an actor, it can be taken, and put back */ public static class Chopstick extends AbstractLoggingFSM<CS, TakenBy> { { // A chopstick begins its existence as available and taken by no one startWith(CS.Available, new TakenBy(context().system().deadLetters())); // When a chopstick is available, it can be taken by a some hakker when(CS.Available, matchEventEquals(Take, (take, data) -> goTo(CS.Taken).using(new TakenBy(sender())).replying(new Taken(self())))); // 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 when(CS.Taken, matchEventEquals(Take, (take, data) -> stay().replying(new Busy(self()))). event((event, data) -> (event == Put) && (data.hakker == sender()), (event, data) -> goTo(CS.Available).using(new TakenBy(context().system().deadLetters())))); // Initialze the chopstick initialize(); } } /** * Some fsm hakker states */ public static enum HS { Waiting, Thinking, Hungry, WaitForOtherChopstick, FirstChopstickDenied, Eating } /** * Some state container to keep track of which chopsticks we have */ public static final class TakenChopsticks { public final ActorRef left; public final ActorRef right; public TakenChopsticks(ActorRef left, ActorRef right) { this.left = left; this.right = right; } } /* * A fsm hakker is an awesome dude or dudette who either thinks about hacking or has to eat ;-) */ public static class Hakker extends AbstractLoggingFSM<HS, TakenChopsticks> { 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; } { //All hakkers start waiting startWith(HS.Waiting, new TakenChopsticks(null, null)); when(HS.Waiting, matchEventEquals(Think, (think, data) -> { System.out.println(String.format("%s starts to think", name)); return startThinking(Duration.create(5, SECONDS)); })); //When a hakker is thinking it can become hungry //and try to pick up its chopsticks and eat when(HS.Thinking, matchEventEquals(StateTimeout(), (event, data) -> { left.tell(Take, self()); right.tell(Take, self()); return goTo(HS.Hungry); })); // 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 when(HS.Hungry, matchEvent(Taken.class, (taken, data) -> taken.chopstick == left, (taken, data) -> goTo(HS.WaitForOtherChopstick).using(new TakenChopsticks(left, null))). event(Taken.class, (taken, data) -> taken.chopstick == right, (taken, data) -> goTo(HS.WaitForOtherChopstick).using(new TakenChopsticks(null, right))). event(Busy.class, (busy, data) -> goTo(HS.FirstChopstickDenied))); // 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 :-) when(HS.WaitForOtherChopstick, matchEvent(Taken.class, (taken, data) -> (taken.chopstick == left && data.left == null && data.right != null), (taken, data) -> startEating(left, right)). event(Taken.class, (taken, data) -> (taken.chopstick == right && data.left != null && data.right == null), (taken, data) -> startEating(left, right)). event(Busy.class, (busy, data) -> { if (data.left != null) left.tell(Put, self()); if (data.right != null) right.tell(Put, self()); return startThinking(Duration.create(10, MILLISECONDS)); })); // 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 when(HS.FirstChopstickDenied, matchEvent(Taken.class, (taken, data) -> { taken.chopstick.tell(Put, self()); return startThinking(Duration.create(10, MILLISECONDS)); }). event(Busy.class, (busy, data) -> startThinking(Duration.create(10, MILLISECONDS)))); // When a hakker is eating, he can decide to start to think, // then he puts down his chopsticks and starts to think when(HS.Eating, matchEventEquals(StateTimeout(), (event, data) -> { left.tell(Put, self()); right.tell(Put, self()); System.out.println(String.format("%s puts down his chopsticks and starts to think", name)); return startThinking(Duration.create(5, SECONDS)); })); // Initialize the hakker initialize(); } private FSM.State<HS, TakenChopsticks> startEating(ActorRef left, ActorRef right) { System.out.println(String.format("%s has picked up %s and %s and starts to eat", name, left.path().name(), right.path().name())); return goTo(HS.Eating).using(new TakenChopsticks(left, right)).forMax(Duration.create(5, SECONDS)); } private FSM.State<HS, TakenChopsticks> startThinking(FiniteDuration duration) { return goTo(HS.Thinking).using(new TakenChopsticks(null, null)).forMax(duration); } } /* * 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]), name)); 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 examplesHere is a short list of links related to this Akka DiningHakkersOnFsm.java source code file: |
... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2024 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.