Programming for fun and profit

Programming tutorials, problems, solutions. Always with code.

Java CyclicBarrier – game simulation

Java CyclicBarrier is very convenient synchronization tool for writing concurrent simulations. In this post we’ll show how it works and write a game simulation.

How to use CyclicBarrier

CyclicBarrier initialization

CyclicBarrier is a synchronization point for a number of parties (threads/runnables/tasks). It is created with the number of parties it should wait on and (optionally) a Runnable action to execute after all of them will reach the barrier. Then threads are released an will run again.

Here’s the most important initialization part:

// Action to run when all Threads will hit the barrier:
Arbiter action = new Arbiter(executor, 10); // 10 rounds

// Number of threads to wait for:
int numberOfPlayers = 2;

CyclicBarrier barrier = new CyclicBarrier(numberOfPlayers, action);

// Parties to synchronize on the barrier:
Runnable player1 = new Player(barrier, "Daenerys");
Runnable player2 = new Player(barrier, "Night's King");

Synchronization on CyclicBarrier

To notify the barrier that our task is done we have to call await() method:

public void run() {
    // Tell the barrier that we've finished:

This will hang our task to wait for the others to complete. Use await(long timeout, TimeUnit unit) to wait only for some time.

Game simulation example

In this simple game Daenerys is fighting with Night’s King. In each round both of them pick weapons randomly. The winner is decided based on the highest number of wins in 10 games. It won’t hit PS4 top titles, but at least shows how CyclicBarrier can be used. ;-)

Game runner

Performs the initialization of the elements participating in the simulation and starts it:


import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CyclicBarrierGame {

    public static void main(String[] args) {
        ExecutorService executor = Executors.newCachedThreadPool();

        // Action to run when all Threads will hit the barrier:
        Arbiter arbiter = new Arbiter(executor, 10);

        // Number of threads to wait for:
        int numberOfPlayers = 2;

        CyclicBarrier barrier
            = new CyclicBarrier(numberOfPlayers, arbiter);

        Player player1 = new Player(barrier, "Daenerys");
        Player player2 = new Player(barrier, "Night's King");

        arbiter.setPlayers(player1, player2);

        System.out.printf("Starting the game: %s vs %s%n",

Player actions

Players are Runnables that will be synchronized on the barrier. In each round a player picks a random weapon and notifies CyclicBarrier that it has finished:


import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

class Player implements Runnable {

    private static final Random RAND = new Random();
    private final CyclicBarrier roundBarrier;

    public final String name;
    public volatile Weapons weapon;
    public volatile boolean gameOver;

    public Player(CyclicBarrier roundBarrier, String name) {
        this.roundBarrier = roundBarrier; = name;

    public void run() {
        try {
            while (!gameOver) {
                weapon = pickRandomly();
        } catch (InterruptedException e) {
            // this one is ok
        } catch (BrokenBarrierException e) {
            // Something funny has happened!
            throw new RuntimeException(e);

    private Weapons pickRandomly() {
        return Weapons.values()


The role of the arbiter is to judge which player has won based on their weapon selection. When the players have played given number of games it tells who has won the whole game:


import java.util.EnumMap;
import java.util.concurrent.ExecutorService;

import static;
import static;
import static;

class Arbiter implements Runnable {

    // Table that decides which weapon wins/draws/loses
    // to other kinds of weapon:
    private static EnumMap<Weapons,EnumMap<Weapons,Integer>>
        SCORING_TABLE = new EnumMap<>(Weapons.class);

    static {
        EnumMap<Weapons, Integer> scores
            = new EnumMap<>(Weapons.class);
        scores.put(Ice, -1);
        scores.put(Fire, 0);
        scores.put(Water, 1);
        SCORING_TABLE.put(Fire, scores);

        scores = new EnumMap<>(Weapons.class);
        scores.put(Water, -1);
        scores.put(Ice, 0);
        scores.put(Fire, 1);
        SCORING_TABLE.put(Ice, scores);

        scores = new EnumMap<>(Weapons.class);
        scores.put(Fire, -1);
        scores.put(Water, 0);
        scores.put(Ice, 1);
        SCORING_TABLE.put(Water, scores);

    private final ExecutorService executor;
    private final int maxGames;
    private Player player1;
    private Player player2;
    private int player1Wins;
    private int player2Wins;
    private int draws;

    public Arbiter(ExecutorService executor, int maxGames) {
        this.executor = executor;
        this.maxGames = maxGames;

    public void setPlayers(Player player1, Player player2) {
        this.player1 = player1;
        this.player2 = player2;

    public void run() {
        System.out.printf("%s vs %s%n",
                player1.weapon, player2.weapon);

        switch (fight()) {
            case -1: ++player1Wins; break;
            case  0: ++draws;       break;
            case  1: ++player2Wins; break;

        if (playedGames() == maxGames) {
            player1.gameOver = true;
            player2.gameOver = true;
            System.out.printf("%s %d : %d %s, %d draws%n",
          , player1Wins,

    private int fight() {
        return SCORING_TABLE

    private int playedGames() {
        return player1Wins + player2Wins + draws;

Results of the game

The above code produces the following output:

Starting the game: Daenerys vs Night's King
Ice vs Ice
Ice vs Water
Fire vs Ice
Ice vs Water
Ice vs Fire
Ice vs Fire
Water vs Fire
Ice vs Water
Fire vs Ice
Water vs Ice
Daenerys 6 : 3 Night's King, 1 draws

The important thing here is that CyclicBarrier was waiting in each round for the threads to finish their work and only then executed the action.

As you can see the Arbiter has been executed 10 times to judge the results, and then stopped the game.

Share with the World!