package fj.demo.concurrent;
import static fj.Bottom.error;
import fj.Unit;
import fj.control.parallel.Strategy;
import fj.control.parallel.Actor;
import fj.function.Effect1;
import java.text.MessageFormat;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Programming with concurrent side-effects.
* Example of parallel synchronous messaging using Actors in Functional Java.
* Author: Runar
*/
@SuppressWarnings("ArithmeticOnVolatileField")
public class PingPong {
private final int actors;
private final int pings;
private final Strategy<Unit> s;
private final Actor<Integer> callback;
private volatile int done;
public PingPong(final ExecutorService pool, final int actors, final int pings) {
this.actors = actors;
this.pings = pings;
s = Strategy.executorStrategy(pool);
// This actor gives feedback to the user that work is being done
// and also terminates the program when all work has been completed.
callback = Actor.queueActor(s, i -> {
done++;
if (done >= actors) {
System.out.println("All done.");
pool.shutdown();
} else if (actors < 10 || done % (actors / 10) == 0)
System.out.println(MessageFormat.format("{0} actors done ({1} total pongs).", done, pings * done));
});
}
public static void main(final String[] args) {
if (args.length < 3)
throw error("This program takes three arguments: number_of_actors, pings_per_actor, degree_of_parallelism");
final int actors = Integer.parseInt(args[0]);
final int pings = Integer.parseInt(args[1]);
final int threads = Integer.parseInt(args[2]);
new PingPong(Executors.newFixedThreadPool(threads), actors, pings).start();
}
public final void start() {
// We will use one Pong actor...
final Pong pong = new Pong(s);
// ...and an awful lot of Ping actors.
for (int i = 1; i <= actors; i++) {
new Ping(s, pings, pong, i, callback).start();
if (actors < 10 || i % (actors / 10) == 0)
System.out.println(MessageFormat.format("{0} actors started.", i));
}
}
}