In this practice we will create an implementation of John Conway’s Game of Life cellular automaton. We will use multi-threading to make it faster.

Download these classes:

Resources:

Exercises:

  1. Create new classes GameOfLife and GOLThread. The latter extends Thread. An object of GameOfLife should use, and keep record of, a number of threads (GOLThread).

    Create the method setThreadCount that sets the number of threads. This number is taken as parameter. First, it calls the method exiting (see below) on each thread, and it waits for the threads to terminate using join. The method exiting signals the thread that it should terminate. Second, setThreadCount starts the given number of threads.

    Make sure that only one thread can execute setThreadCount at a time using synchronization.

    Add a method start which sets the number of threads to one.

  2. Add a field to the GOLThread that acts as a work queue. It is a sequence Point objects.

    Create a method that adds a Point to the queue.

    Add flags exiting and pointsProcessed. Create methods which set these flags.

    Add a reference to an object of GameOfLife that created this GOLThread. This should be received in the constructor.

    Also, add the method getEnv to GameOfLife which returns the current environment.

    Override the run method. It should process points from the queue until the flag exiting is set. When the queue is empty and exiting is not set, it should sleep for 100ms. We will implement processing of a Point later.

  3. Create a class Environment. It records living cells and how many surrounding cell each place has. That is, an environment is a two-dimensional space of cells and empty spaces.

    Constructor of GameOfLife should take an Environment as argument.

    Write the method next that creates a new evironment. In the new environment, cells with 2 or 3 neighbour cells remain living, and at empty places with 3 neighbour cells a new living cell should be created.

  4. Create a function step in GameOfLife. This should distribute points among the threads. After all living cell was put into one of the threads queues, it should notify each GOLThread that the points have been processed.

    Make sure that only one thread can execute step at a time using synchronization.

    Change method run in GOLThread. When all points are processed, it should notify its GameOfLife creator. The method step in GameOfLife should only continue if all threads notified it (use the CountDownLatch). After that step can replace the environment with the result of calling next on the current environment.

  5. In Environment, the number of surrounding cells of each place should be stored in AtomicIntegers.

    Create the method increment that receives a Point, and increments the number of surrounding cells associated to that Point by one. Beware that increment will be used by multiple threads at the same time. Multiple threads should not modify the same collection without proper locking mechanism!

    The run in GOLThread should call the method increment on each neighbour of a cell that was put in the queue.

  6. Extra exercise. Make GameOfLife AutoClosable.