Writing concurrent application could be painful ! Not with JRebirth
JRebirth is multi-threaded, not only by using Task Worker provided by JavaFX APIs. JRebirth has got its own Thread to manage local events (called waves) allowing components to communicate with each others. It also allows to manage multiple threads in a very simple manner with its included thread pool.
Thus all inner JRebirth tasks are processed into a custom thread and don’t infer with the JavaFX Application Thread which have to manage user events and some UI instantiation.
Lags, UI Freeze … are lost to history :D
What happens when you debug a JRebirth application ? You can observe a lot of threads, but don’t be scared !! Everything is at the right isolated place doing the right thing.
The most important are :
Other threads are related to JavaFX platform, JRebirth only creates one thread and two Thread Pools.
JRebirth Thread Pool and High Priority Thread Pool have the same size, computed like this: - Number of available Core * threadPoolSizeRatio parameter
The default parameter value is 2, so each thread pool will have a size of 16 on Core i7 (Quad Core with HyperThreading). You can use a double value to divide this amount if you think that it can disturb your platform performances (0.250 value will only provide a thread pool size of 2 on a such platform).
Obviously a minimum size of 1 will be used if your thread pool ratio is too low or if the platform has not enought cpu cores.
Each thread shall manage specific tasks, let’s see their aims.
JavaFX Application Thread is the graphical thread of the toolkit, you shouldn’t perform long task into it, but you must update all node attached to the displayed scene into it. It’s the equivalent of the former EDT (Event Dispatch Thread) in Swing. If you try to update a node attached to the main JavaFX scene outside it you will obtain an ugly Exception.
JRebirth Internal Thread is the internal thread of JRebirth Application Framework. It will be used to host the communication engine between all JRebirth Components. If you start a long task into it it will freeze all communication tasks because all runnable added will be executed synchronously according to FIFO rule (First-In First-Out).
JRebirth Thread Pool is designed to perform all other long task your application require, you just have to remember that any graphical update still require to be done into JAT. Moreover any JRebirth internal configuration must be performed into JIT (ie: listen a WaveType).
High Priority Thread Pool has been added to be able to assign a priority to a long task. On small platform or when using very long task, the JTP can be overloaded and we should create an higher priority task to trigger an User interface refresh. The HPTP will be used to trigger higher priority task when JTP is full. It has same settings than JTP.
JAT is the the graphical thread of the JavaFX toolkit (identical to Swing EDT), all UI tasks must be perform into it only if a direct link can be establish between the graphical component and the displayed scene. So if you call setText(“myText”) on a Text node:
JavaFX toolkit let you prepare some tree of node into a separate thread and then attached it to the displayed scene. This is how JRebirth load and display any Model, the PrepareModelCommand will run into JTP to create the Model root Node with all its children. Then the AttachModelCommand will be run into JAT to attach the model root node into another node already displayed into the Scene.
JIT does same things than JAT but for managing communication between JRebirth Components. It mainly manage the JRebirth Notifier. So any call to Notifier outside JIT will raise a new Exception. For a standrad usage it will be totally transparent for you.
But sometimes you can want to trigger a command within JIT to be sure it will be executed before another wave is handled. This is a really risky task, do it on your own responsability.
JRebirth provides 2 thread pools to run long task asynchronously without freezing neither the User Interface (JAT) nor JRebirth Messaging (JIT).
All Wave processing tasks are automatically done into the JIT.
When the JRebirth Framework needs to update UI (thanks to Model area), it’s done automatically done into the JAT. No matters to have !
But when you call a component directly (synchronous method: getCommand, getService, getModel), your call is processed into the current thread, so you must pay attention to what you are doing.
When you are into the JIT you can use JRebirth.runIntoJAT that call internally Platform.runLater to perform UI updates.
JRebirth Framework offers some default commands to do the trick (DefaultUiCommand). Moreover if you send a Wave with a WaveType listened by a model, it will be automatically processed into the JAT (Cool JRebirth Magic).
When you are in the JAT you must use JRebirth.runIntoJIT that call internally JRebirthThread.runLater to run tasks into the core thread. You can also use JRebirth.runIntoJTP to run task within a slot of available thread pool.
JRebirth Framework offers some default commands to force to run into JIT & JTP (DefaultCommand and DefaultPoolCommand). You can also send a wave that will trigger a command, or call a service into another thread that JAT.
Sometimes you want to run a task within another thread but synchronously. It’s a bad idea but can be required in some particular cases. You can use custom methods:
Each will wait synchronously the end of the task run within the wanted thread.
If you want to call a service which make an asynchronous call to a remote server. You can use a Service Task method to initiate the call (By default this call will be managed into JRebirth Thread Pool: JTP), but the return must be managed into the JAT:
When components communicate using Wave, any Wave handler method can be managed in a specific thread by using @RunInto annotation.
The default behavior is:
3 kinds of Wave are managed differently (not customizable) because they trigger special Component interaction: