JavaFX articles‎ > ‎

Real multi-threading in JavaFX

posted Nov 5, 2013, 1:40 PM by Sergey Malenkov   [ updated Nov 5, 2013, 1:42 PM ]

I developed my first implementation of the Reversi game on BASIC 20 years ago. Since then, I ported it on each programming language I studied: Turbo Pascal with graphics library and Turbo Vision, C with the Windows API, C++ with the ClanLib, Java AWT applet, and Swing application with Java2D. Now I am ready to publish yet another implementation, on JavaFX Script.

JavaFX 1.3 applet: Reversi

This game allows to compete with one of the algorithms as well as to see how these algorithms compete with each other. The Sergey algorithm is based on the Minimax algorithm with a simple table of game piece weights where the calculation depth is 6. The Pavel algorithm is developed by my colleague, and I have got it from the official JavaFX site. But I had to add the following constructor:

public Board(GameBoard board) { this(); Object dark = board.getFriend(); Object light = board.getEnemy(); int pos = 11; for (int y = 0; y < 8; y++, pos += 2) { for (int x = 0; x < 8; x++, pos++) { Object piece = board.getPiece(x, y);[pos] = (piece == dark) ? PIECE_DARK : (piece == light) ? PIECE_LIGHT : PIECE_EMPTY; } } this.movePiece = PIECE_DARK; prepareMoves(); }

When I increased the calculation depth, I discovered that the search function started blocking the UI. The rationale is that the Timeline class invokes all functions from key frames on the thread which renders UI. I decided to override the abstract JavaTaskBase class and implement the RunnableFuture interface to avoid extra entities:

public class JavaTask extends JavaTaskBase, RunnableFuture { override function create() { this } override function run() { // do something } }

However, I found out that the RunnableFuture interface must be implemented on Java, i.e. it is prohibited to use FX objects. It seems to me that in this case the JavaTaskBase class should not be an abstract class. It should be initialized via a public variable as in my JavaTask class:

public class JavaTask extends JavaTaskBase { public-init var runnable: RunnableFuture on replace { start() } override function create() { runnable } }

Note that JavaFX does not support thread synchronization. Be careful!

If you know how to use the invokeLater method of the EventQueue class to split a long tasks, you can use the deferAction method of the FX class in the same way. This method invokes a function on the thread which renders the UI. Thus, you don't need synchronization in this case.

Also Baechul's Weblog will be useful.

I run the algorithm competition during the past weekend. Below are the results:

  • Pavel versus Sergey: 5653 wins, 363 draws, 8605 losses;
  • Sergey versus Pavel: 8563 wins, 299 draws, 6612 losses.

In addition, I discovered that my algorithm is often wins, turning all the opponent's pieces. The reason is that Pavel uses an algorithm to minimize available moves of the opponent. He promised to complete the evaluation function soon.

Would you like to join the battle of algorithms?

PS. This article was originally posted on the site.