I’m (re-)launching Ribomation
During the 90s I was running my own company Ribomation, devoted to training (and consulting) in advanced software development areas. In the beginning it was mostly C, C++, OOAD and threads programming in Linux. Towards the end of the 90s, it was Java only - all sorts of Java related topics. When the dot-com morphed into the dot-gone, I terminated the business and spend some years abroad.
Almost ten years later it is time to start the company engine again and steer Ribomation out at the ocean. As always I will focus on emerging and disruptive technologies. Cloud Computing (CC) is definitely of that kind. CC will change the way we design and develop applications.
There are three use cases for CC:
- Extra server(s)
- Elastic (scalable) applications
- Massive data computation
If you need some extra capacity, for example testing server, number 1 above apply. If you need to design applications that can scale to 100.000s of users, number 2 apply. And, if you need to process large amount of data, number 3 applies.
Using TMI instead of Actors
Here in Sweden the spring has finally arrived and one of the duties I have to do is switching from winter to summer tires on my car. I did that this morning and while waiting in the garage I was reading the two articles about Actor concurrency in JavaWorld. The first article described the actor semantics and how it was realized in the Erlang programming language and the second article described various ways to realize actors on top of the JVM, such as Scala, Groovy and Java it self.
I wasn’t aware of the multitude of actors implementations in Java, as the second article describe. The author Alex Miller implemented the same problem (Rock-Paper-Scissors) for each actor realization and compared the code and effort. This was interesting reading indeed.
Thread Method Invocation (TMI)
Many years ago, back in 2002 to be exact, I implemented a library for thread method invocation (TMI) in Java. The idea was to provide various message passing techniques to Java, ranging from simple mailboxing to non-deterministic rendezvous. The library is essentially different implementation of message queues.
Together with the library I wrote a (long) tutorial that started from the very beginning with motivation of why synchronized and wait/notify/notifyAll are needed and then step-by-step moved up in the abstraction level via different forms of message passing, ending in non-determinsitic rendezvous, inspired by the Ada programming language. The article was submitted to JavaWorld, but was declined. After that I was busy with so many other things that the idea and the libray went into limbo. Perhaps it might resurrect nowadays.
After having read the second article with its various Rock-Paper-Scissors implementations, I couldn’t resist the temptation to do my own implementation of Rock-Paper-Scissors using TMI. The rest of this post describes my implementation.
Before I continue, let’s state first that TMI is not an actors model. It is close in spirit, becuase it’s a message passing model, but do not honor the value passing semantics. You can pass what ever object you want as a sender argument or as a response object (rendezvous). Still I consider TMI be a very useful concurrency model and simplifies designing thread based Java programs a lot.
Rock-Paper-Scissors using TMI
The main class is simple and straight forward, let’s show it first. It creates two players and a coordinator and kicks the latter to start the game. The program runs for a specified number of seconds.
public class RockPaperScissorsUsingTMI {
public static final String ROCK = "rock";
public static final String PAPER = "paper";
public static final String SCISSORS = "scissors";
public static void main(String[] args) throws InterruptedException {
int runIntervalInSeconds = 20;
if (args.length > 0) runIntervalInSeconds = Integer.parseInt( args[0] );
Player p1 = new Player(1);
Player p2 = new Player(2);
Coordinator c = new Coordinator(p1, p2);
c.start(); p1.start(); p2.start();
c.startPlay();
Thread.sleep(runIntervalInSeconds * 1000);
}
}
Here is a sample output of running the program.
>java -jar RockPaperScissorsUsingTMI-1.0.jar 15 0) Player-1: scissors -> paper 1) Player-1: scissors -> paper 2) Player-1: scissors -> paper 3) Player-1: rock -> scissors 4) Player-2: scissors -> paper 5) Player-2: rock -> scissors 6) TIE: scissors 7) TIE: scissors 8 ) Player-2: rock -> scissors 9) Player-2: scissors -> paper 10) Player-2: rock -> scissors 11) Player-1: rock -> scissors 12) Player-2: rock -> scissors 13) Player-1: scissors -> paper 14) Player-2: rock -> scissors 15) TIE: paper 16) Player-1: rock -> scissors 17) Player-2: paper -> rock 18) TIE: rock >
The Player
The player class below is simple, but illustrates the TMI realization. In this case I have chosen to be close to the actors model and are using an unbounded message queue. The interesting methods are play() and receive() which shows the ’sender’ side and the ‘receiver’ side of a message queue. The sender invokes play(), which inserts a message into the queue. Because the queue is unbouded, this is not a blocking call. It’s easy to change the queue to a rendezvous queue, which results in the sender are blocked until the receiver puts a reply. Inside the run() method, a player recieves the coordinator. The player is blocked as long as the input queue is empty. Then it waits for a random amout of time and performs a move. It responds back to the coordinator using itself as argument.
public class Player extends Thread {
private static final List<String> moves = Arrays.asList(ROCK, PAPER, SCISSORS);
private static final Random r = new Random();
private MessageQueue playMsgs = new UnboundedMessageQueue();
private String move;
public Player(int id) {
super("Player-"+id);
setDaemon(true);
}
public void run() {
try {
while (true) {
Coordinator c = receive();
delay( r.nextInt(1000) );
move = makeMove();
c.throwResult(this);
}
} catch (InterruptedException e) {System.out.println(getName()+" Interrupted");}
}
public void play(Coordinator master) {
try {
playMsgs.put(master);
} catch (InterruptedException e) { }
}
private Coordinator receive() {
try {
return (Coordinator) playMsgs.get();
} catch (InterruptedException e) {return null;}
}
private String makeMove() {
return moves.get( r.nextInt(moves.size()) );
}
public String getMove() {
return move;
}
protected Player setMove(String move) {
this.move = move;
return this;
}
private void delay(int numMilliSecs) {
try {
sleep(10 + numMilliSecs);
} catch (InterruptedException e) { }
}
}
The Coordinator
The coordinator is slightly more complex, due to its responsibilities. It waits for a start message, then ask each player to play and receives the throw messages in either order. It then evalutes who won this round. The concurrency part is not very complicated. It has two unbouded queues, one for each message type. And for each message type it has a public sender method (startPlay/throwResult) and a private receive method (receiveStart/receiveThrow). The Permutation class is just a helper for computing or winner.
public class Coordinator extends Thread {
private MessageQueue startMsgs = new UnboundedMessageQueue(),
throwMsgs = new UnboundedMessageQueue();
private Player player1, player2;
public Coordinator(Player player1, Player player2) {
super("Coordinator");
this.player1 = player1;
this.player2 = player2;
setDaemon(true);
}
public void run() {
try {
for (int count = 0; true; count++) {
receiveStart();
player1.play(this);
player2.play(this);
Player first = recieveThrow(),
second = recieveThrow();
if (isTie(first, second)) {
System.out.printf("%4d) %8s: %s%n", count, "TIE", first.getMove());
} else if (isWinning(first, second)) {
System.out.printf("%4d) %8s: %s -> %s%n",
count, first.getName(), first.getMove(), second.getMove());
} else {
System.out.printf("%4d) %8s: %s -> %s%n",
count, second.getName(), second.getMove(), first.getMove());
}
this.startPlay();
}
} catch (InterruptedException e) {System.out.println(getName()+" Interrupted");}
}
public void startPlay() throws InterruptedException {
startMsgs.put(this);
}
private void receiveStart() throws InterruptedException {
startMsgs.get();
}
public void throwResult(Player p) throws InterruptedException {
throwMsgs.put(p);
}
private Player recieveThrow() throws InterruptedException {
return (Player) throwMsgs.get();
}
protected boolean isWinning(Player first, Player second) {
Permutation permutation = new Permutation(first, second);
return permutation.dominates(ROCK , SCISSORS) ||
permutation.dominates(PAPER , ROCK) ||
permutation.dominates(SCISSORS, PAPER);
}
protected boolean isTie(Player first, Player second) {
return new Permutation(first, second).tie();
}
private static class Permutation {
private Player first, second;
private Permutation(Player first, Player second) {
this.first = first;
this.second = second;
}
public boolean dominates(String m1, String m2) {
return first.getMove().equals(m1) && second.getMove().equals(m2);
}
public boolean tie() {
return first.getMove().equals( second.getMove() );
}
}
}
Source code
My application is developed using Maven, which means it very easy to download and unpack the sources and then type
mvn package java -jar target\RockPaperScissorsUsingTMI-1.0.jar 60

