JavaFX beans/properites and multithreading - java

I must say that I'm new to Java and JavaFX (less than 2 months), and also my UML skills are not perfect, so I might have used wrong blocks or/and connectors on the diagram :) But I hope you get an idea.
I have an order management app with a following (simplified to essentials) design:
OMS app design
Put very simply, the JavaFX GUI displays in a table view what is happening (i.e. the current state of the orders) between the client (that sends orders) and the broker (on the other end of the network connection). Order Manager is the only entity that has access to modify the model (i.e., the list of orders and their fields), and all methods modifying the model are synchronised (so it's safe to call them from any thread).
The orders are JavaFX beans, with different fields implemented as JavaFX Properties. These properties are bound to table columns in the GUI, so whenever the Order Manager updates a field, the change is propagated to the GUI via the binding mechanism.
Now, because the property binding mechanism is not thread-safe (see the following rule:
An application must attach nodes to a Scene, and modify nodes that are already attached to a Scene, on the JavaFX Application Thread.
), I have to wrap all the code modifying those fields, in Platform.runLater() calls, for example:
public void onOrderCanceled(int id, String reason) {
Order order = orderbook.get(id);
if(order == null) {
throw new IllegalArgumentException("Order "+id+ " not found");
}
Platform.runLater(() -> {
order.setReason(reason);
order.setStated(CANCELED);
subscribers.foreach(sub -> sub.notifyUpdated(order));
});
}
This approach has the following unpleasant implications:
The client notification is delayed by an arbitrary time (till the GUI thread finishes processing its message queue). Reason: I cannot notify the client before the order fields are updated (or it will have incorrect data), and I can only update the fields in the GUI thread.
Because the state of the order is not modified right away but at some future point, there exists for some time an incoherence between the order object and the actual order state.
If the GUI thread gets blocked or becomes very slow (because of bugs or design flaws), the client code is blocked or slowed down (while waiting for the notification that is stuck in the GUI thread's message queue).
Is there a better way of doing that? Ideally, I would like a solution that:
Allows the client code to communicate with the networking layer (via the order manager) as fast as possible, i.e. without waiting for the GUI to catch-up
The GUI is allowed to lag behind a little bit, but must not "skip" field updates, or at least never drop the most recent update (which is the most relevant)
Rely on the FX property binding architecture to update the GUI (which I find very convenient)
I feel that I need to create another "model" for the GUI that will be updated in the FX thread only, while the "real" model will be used by the order manager and the client code, and I need to ensure to maintain the two models in sync (which is creepy).
Was FX designed without multithreading in mind? I had a look on the Task and Service interfaces, but is doesn't look like something appropriate (in my case, GUI doesn't initiates a task - it comes from an external source, the client code or the network).
Thanks in advance!

If I understand this implementation correctly, you are performing the notification to remote clients on the FX Application Thread. You're doing this because you need to send the clients the updated version of the Order object, and since this object is bound to the table, changes to its state can only happen on that thread.
This is somewhat perilous, as those remote notifications may take time, and so you may block the UI thread, causing a lack of responsiveness. Additionally, you are forcing the logic of the application to wait for the (potentially blocked) UI thread. This is the opposite way around to the way you should be doing things: your application logic should flow in a thread of execution in a natural way, and you should arrange for the FX Application Thread to show the latest version of the data in as lightweight a way as possible on each frame rendering.
I think what you need here is a separate, immutable class to represent the updates. You'll send those to your clients, and then on successful notification update the UI, instead of driving the application from the UI. So something like
public abstract class Update {
private final int orderId ;
public Update(int orderId) {
this.orderId = orderId ;
}
public abstract void performUpdate(Order order) ;
public int getOrderId() {
return orderId ;
}
}
and
public class Cancelation extends Update {
private final String reason ;
public Cancelation(int orderId, String reason) {
super(orderId);
this.reason = reason ;
}
public String getReason() {
return reason ;
}
#Override
public void performUpdate(Order order) {
if (order.getId() != getOrderId()) {
throw new IllegalArgumentException("Wrong order");
}
order.setReason(reason);
order.setState(CANCELED);
}
}
Now in your application code you can do something like
public void onOrderCanceled(int id, String reason) {
Order order = orderbook.get(id);
if(order == null) {
throw new IllegalArgumentException("Order "+id+ " not found");
}
Task<Update> updateTask = new Task<Update>() {
#Override
public Update call() throws Exception {
Update update = new Cancelation(id, reason);
subscribers.forEach(sub -> sub.notifyUpdate(update));
return update ;
}
};
updateTask.setOnSucceeded(e -> updateTask.getValue().performUpdate(order));
updateTask.setOnFailed(e -> {
Exception exc = updateTask.getException();
// handle exception
});
subscriberNotification.execute(updateTask);
}
Now you schedule updates in an executor dedicated to that particular functionality, and then update the UI when you know the notification has happened. In other words, the UI responds to the application logic, instead of the other way around. Your clients now receive the details of the update, and presumably they have their own representation of the Order (perhaps instances of the same class), and can update their own representations using the information in the Update. Note this will likely save you network traffic too (probably the biggest bottleneck in your application), because you only communicate the changes, instead of the entire object. Of course, this might entail some major refactoring of your code (sorry about that...).
It's going to be important that the updates are all transmitted in the correct order, so you should use a single thread of execution for managing them. In other words, you need something like
private final Executor subscriberNotification = Executors.newSingleThreadedExecutor();

Related

Platform.runLater() with Lambda Expression not working

In my program, I often make modifications to the UI using another thread.
The changes look like that:
buffer.add(new Object[]{message.getSecondNode().getUINode(), "red"});
Therefore I buffer these modifications in order to not overload the UI.
But in the following method the program does not make all the changes delivered in the buffer.
private void changeColor(List<Object[]> buffer) {
Platform.runLater(() -> {
for (Object[] object : buffer) {
if (object[0] instanceof UIEdge) {
UIEdge edge = (UIEdge) object[0];
edge.setColor((String) object[1]);
} else if (object[0] instanceof UINode) {
if ((String) object[1] == "red")
Util.print("");
UINode node = (UINode) object[0];
node.getEllipse().setFill(Paint.valueOf((String) object[1]));
}
}
});
}
In the following picture you see that the buffer has a different size in the method to its global size in the program.
Does anyone know why?
you might want to consider using JavaFX Service and Task instead of a buffer to make updates. These are JavaFX classes that are provided to make multi-threading easier in a JavaFX application.
https://docs.oracle.com/javase/8/javafx/api/javafx/concurrent/Task.html
Because the Task is designed for use with JavaFX GUI applications, it ensures that every change to its public properties, as well as change notifications for state, errors, and for event handlers, all occur on the main JavaFX application thread.
https://docs.oracle.com/javase/8/javafx/api/javafx/concurrent/Service.html
The Service by default uses a thread pool Executor with some unspecified default or maximum thread pool size. This is done so that naive code will not completely swamp the system by creating thousands of Threads.
Here's a brief tutorial if your not already familiar with them.
https://docs.oracle.com/javase/8/javafx/interoperability-tutorial/concurrency.htm

"Asynchronous while loop" in JavaFX thread

When I need to do an indeterminate number of pieces of work in the JavaFX thread without blocking the user interface, I use this class
public class AsyncWhile {
private final IntPredicate hook;
private int schedCount = 0;
private boolean terminated = false;
private int callCount = 0;
private static final int schedN = 1;
public AsyncWhile(IntPredicate hook) {
this.hook = hook;
schedule();
}
public void kill(){
terminated = true;
}
private void schedule(){
while(schedCount < schedN){
Platform.runLater(this::poll);
schedCount++;
}
}
private void poll(){
schedCount--;
if(!terminated){
terminated = !hook.test(callCount++);
if(!terminated){
schedule();
}
}
}
}
like this
asyncWhile = new AsyncWhile(i -> {
// return false when you're done
// or true if you want to be called again
});
// can asyncWhile.kill() should we need to
(
If you need a more concrete example, here I'm reading one line at a time from an InputStream and then parsing and displaying a plot parsed from that line:
asyncWhile = new AsyncWhile(i -> {
String line;
try {
if((line = reader.readLine()).startsWith(" Search complete.")){ // it so happens that this reader must be read in the JavaFX thread, because it automatically updates a console window
return false;
} else {
Task<MatchPlot> task = new ParsePlotTask(line);
task.setOnSucceeded(wse -> {
plotConsumer.accept(task.getValue());
// todo update progress bar
});
executorService.submit(task);
return true;
}
} catch (IOException ex) {
new ExceptionDialog(ex).showAndWait();
return false;
}
});
)
Chaining up runLaters like that feels like a hack. What is the proper way to solve this kind of problem? (By "this kind of problem" I mean the problem that would have been solved by a simple while loop, had it not been for the fact that its contents must run in the JavaFX thread without making the UI unresponsive.)
Recommended
In general, basing a solution off of the PartialResultsTask sample from the Task documentation (which relies on Platform.runLater invocations), is the standard way of solving this problem.
Alternate
Rather than scheduling runLater's you could use a BlockingDeque. In your processing task, you perform your time-consuming process just with a normal while loop, generate non-UI model objects which need to be represented in the JavaFX UI, stick those non-UI model objects into your queue. Then you setup a Timeline or AnimationTimer that polls the queue, draining it as necessary and to pick the items off the queue and represent them in the UI.
This approach is similar (but a bit different) to: Most efficient way to log messages to JavaFX TextArea via threads with simple custom logging frameworks.
Using your own queue in this case is not much different from using the implicit queue runLater invocations go on to, though, with your own queue, you might have a little more control over the process if you need that. It's a trade-off though, as it adds a bit more custom code and complexity, so probably just use the recommended PartialResults sample from Task and, if that doesn't fit your needs, then perhaps investigate the alternative custom queue based approach.
Aside
As a side note, you could use the custom logging framework linked earlier to log console messages from multiple threads to be displayed in your UI. That way you don't need to have your reader.readLine call execute I/O on the JavaFX UI, which is not recommended. Instead, have the I/O performed off the JavaFX UI thread and, as you process items, call into the logging framework to log messages that will eventually show up on the UI (the internal mechanisms within the logging framework take care of ensuring that JavaFX threading rules are respected).
Can you see any danger in using my approach?
Sorry for being non-specific here. I'm not going to directly answer this, but tangentially and not always applicably to your approach, using runLater can cause issues, mostly it is not a concern, but some things to consider:
If you send enough runLater calls faster than they can be processed, eventually you will either run out of memory or some runLater calls will start being ignored (depending on how the runLater system works).
Calls to runLater are sequential, not prioritized, so if there are internal events which are also being runLater, such as handling UI events, those might be delayed while your runLater calls are being processed.
runLater offers no guarantee of when later is. If your work is time sensitive, that might be an issue or at least something you need to account for in your implementation.
The runLater system is likely internally fairly complex and you won't know exactly how it is implemented unless you study the source code pretty closely.
Anything that you run on runLater is going to hold up the JavaFX application thread, probably until all of the outstanding runLater calls are complete
Once you have issued a bunch of runLater calls, you can't easily intersperse their processing over multiple pulses in the JavaFX animation system, they will likely all be executed on the next pulse. So you have to be careful not to send too many calls at once.
Those are just some things that come to mind.
In general though, runLater is a sound mechanism for many tasks and a core part of the JavaFX architecture. For most things the above considerations don't really have any consequence.
Writing quality multi-threaded code is pretty tricky. To the point where it often best avoided where possible, which is what the JavaFX system attempts to do for the most part by making scene graph access single-threaded. If you must do it, then stick to the patterns outlined in the Task documentation or utilizing some of the high level java.util.concurrent systems as much as possible rather than implementing your own systems. Also note that reading multi-threaded code is even trickier than writing it, so make sure what you do is clear to the next person.

switch javafx/jrubyfx scenes after some external event

I'm modeling a prototype that will use JavaFX.
The application will be similar with a kiosk, for self service. however before the client interact with it, the administrator should unlock it. The administrator will be able to send some remote commands, via a dedicated channel (HTTP or IPC or USB device). Examples of command would be: start, stop and reset
How should I do it?
a) Can I have a Task, running in another thread pooling actively an IPC and if there is message there, switch the Scene?
b) to have a reactor running in a thread and as soon receives a command, it pass it to the JavaFX thread.
are both options valid? does exist a third one?
Both your options (a) thread with Task and (b) thread without task are valid.
Recommended Solution
I'd choose option b (thread without a task).
The key part of the solution is the line:
Platform.runLater(() -> MyApplication.changeScene(newData));
Task is good, but probably not best for your situation
Task is good if you have something which is initiated by the UI or JavaFX thread. For example, the user clicks a button and you want to retrieve data from a server based upon that action, feeding back progress reports via messages and progress bar updates as the data is retrieved. So Task is very good for that kind of operation because it has explicit support for things such as the message feedback and progress updates as well as a well defined state model for when the task starts and completes. See invariants code example to understand how Task improves such situations: Platform.runLater and Task in JavaFX.
However, when the initiator of the event is off the JavaFX application thread, there isn't much advantage in using a Task versus just using traditional concurrency utilities. This is because you typically don't need the extra services that the Task is providing such as the progress and message update APIs and its state machine. Also, libraries that are initiating such events typically already have their own thread model setup, so you don't need the extra threading framework provided by a Task.
Using Platform.runLater()
All you really want is a notification that something happened. Now that notification needs to occur on the JavaFX application thread as you can't manipulate items in an active scene using another thread. To get an event passed to the JavaFX application thread, you use the Platform.runLater(runnable) construct.
Sample Code
I won't write Ruby, because I really can't, but here is some code in Java to give you the gist - it's actually really simple.
class DataReader implements Runnable {
private final DataSource dataSource;
public DataReader(String location) {
dataSource = new DataSource(location);
Thread thread = new Thread(this);
thread.setDaemon(false);
thread.start();
}
public void run() {
while (dataSource.hasData()) {
MyImmutableObject newData = dataSource.getSomeData();
Platform.runLater(() -> MyApplication.changeScene(newData));
}
}
}
class MyApplication extends Application {
public void changeScene(MyImmutableObject newData) {
FXMLLoader loader = new FXMLLoader(
getClass().getResource(
"layout.fxml"
)
);
UIController controller =
loader.<UIController>getController();
controller.initData(newData);
Scene scene = new Scene((Pane) loader.load());
stage.setScene(newScene);
}
}
The above sample makes use of fictional DataSource, MyImmutableObject and UIController classes and a fictional FXML template to demonstrate the concept (so the snippet is not a standalone runnable thing). The FXML loading concepts come from: Passing Parameters JavaFX FXML. The sample code creates its own thread, but if whatever you library you are using already creates threads itself (which is likely), you don't need to create another one, you can just add appropriate hooks into the existing library with Platform.runLater calls to get the event notification and passing of data between the library threads and your JavaFX application.
Related Questions
There are numerous other questions on Platform.runLater versus Task on StackOverflow:
Javafx: Difference between javafx.concurent and Platform.runLater?
JavaFX 2: background and Platform.runLater vs Task/Service
Additional Questions
in my case, the administrator will be able, in some cases, to send an initial information to the kiosk, almost like an (initialization vector), for example the passport number. With this information, still the Platform.runLater the best solution?
Yes, Platform.runLater is still the best solution. You will have some thread which is alerted when the administrator sends the information to the kiosk (e.g. a servlet on an embedded http server or a jax-rs service) and it can invoke Platform.runLater to update the JavaFX based kiosk UI based on that info.

Concurrency for objects in Java

I am currently working on an exercise in which I have to design a small and simple industrial factory in Java. Basically I've got a warehouse for storage, machines that produce stuff and a GUI that takes commands and informs the user of the current stockpile of the different products, etc.
I've got almost everything working, however, with the limitation that only one machine can produce at a time right now. This is probably due to my approach to the whole exercise. I wanted to start small and just coded tiny units of the program that could work independently and then pieced them together one after another adding more and more logic to the application and implementing all the communication between the different classes, etc.
Now I am at the point where everything seems to be fine and the only thing left to do is to establish concurrency so that I can run several machines at the same time without any problems.
To give you a better understand, I'll try to outline my applications structure:
First there's a GUI and a GUI Controller that assigns the tasks wanted by the user to the other Controllers in the application. It also manages the updates for the GUI (stockpile, ...)
Then I've got the warehouse section with the actual warehouse (HSQLDB, file based, JDBC connection) and a storageController, which controls all tasks regarding the warehouse (store products, remove products, get the stock, ...)
And finally there is the machine section.
There are 3 types of machines. Each type differs only in the product produced. Type 1 and 3 produce the raw products needed for type 2 to produce a final product.
In order to create as many machines as one likes to, I decided to use a Abstract Factory pattern to implement them. That means that I've got an abstractMachineFactory, which holds all the needed attributes (like a machine ID, its status (on/off), ...) and methods including an abstract method "produce(boolean status)". Status = true means that the machine is producing, false means that it's not.
I gave each of the machine types its own class, so that I've got concreteMachineType1, concreteMachineType2 and concreteMachineType3. In there the "produce()" method is implemented specifically to the machine type, i.e. type2's method checks (via the machineController) if there is a big enough stockpile of the raw products that type1 and 3 produce so that it can begin producing.
As the machines should be continually producing, the body executes "while (status=true)". If the stockpile is not big enough, the machine will check again after a certain timeout (via the controller).
And now we come to the machineController. This controller manages all tasks regarding the individual machines. That means creating them, starting/stopping a single or all machines, get supplies from the warehouse, bring the final product from the interim storage to the warehouse, etc.
In order to identify and access my machines, I've implemented different array lists (one for each machine type) in which the machine objects are stored, with the index of the array being the machines' ID. This way I can start/stop a specific machine by accessing the index or start/stop all by parsing through the whole array list.
When starting the machines I also execute the "produce()" method and this is where the problem is at the moment (in my opinion).
This is what happens: I create a few new machines (default is that they are turned off) and then execute my startAllMachines() method. What this method will do is parsing through the array list and executing startMachine() on every single machine object in that list. As said above, startMachine() also calls the produce() method of the machine.
And now I'm basically in an infinite loop, as the produce() method of that machine will run as long as I turn it off, by setting its status value to false. That means that all other machines will not be turned on, so that only this single machine will produce and the rest is in a queue that will never be reached.
I figure that I need different threads to work all machines concurrently, so that each machine is started by a different thread. The problem is that I have no clue on how to achieve this and the basic tutorials I've found didn't help me either. Most of them suggested implementing Runable() and defining a run() method, but this isn't applicable in my scenario (imho). What I think I need is concurrent machine starter objects or something.
I hope some of you can give me hints in how to proceed here.
best regards
daZza
class Machine {
private Thread producerThread;
/**
* Non blocking method that produces fixed amount of stuff and returns.
*/
private void produceStuff() {
// TODO
}
private void startProducing() {
Runnable producingTask = new Runnable() {
public void run() {
produce();
}
};
producerThread = new Thread(producingTask);
producerThread.start();
}
private void stopProducing() {
if (producerThread != null) {
producerThread.interrupt();
}
}
/**
* Check cancellation every time stuff is produced.
*/
private void produce() {
while (!Thread.currentThread().isInterrupted()) {
produceStuff();
}
}
public void start() {
startProducing();
}
public void stop() {
stopProducing();
}
}

Java + Swing: writing code to coalesce change events

I have this data flow, roughly:
DataGenerator -> DataFormatter -> UI
DataGenerator is something that generates data rapidly; DataFormatter is something that formats it for display purposes; and the UI is just a bunch of Swing elements.
I'd like to make my DataGenerator something like this:
class DataGenerator
{
final private PropertyChangeSupport pcs;
...
public void addPropertyChangeListener(PropertyChangeListener pcl) {
this.pcs.addPropertyChangeListener(pcl);
}
public void removePropertyChangeListener(PropertyChangeListener pcl) {
this.pcs.removePropertyChangeListener(pcl);
}
}
and just call this.pcs.firePropertyChange(...) whenever my data generator has new data; then I can just do dataGenerator.addPropertyListener(listener) where listener is responsible for pushing the change forward to the DataFormatter and then to the UI.
The problem with this approach, is that there are thousands of dataGenerator changes per second (between 10,000 and 60,000 per second depending on my situation), and the computational cost of formatting it for the UI is high enough that it puts an unnecessary load on my CPU; really all I care about visually is at most 10-20 changes per second.
Is there any way to use a similar approach, but coalesce the change events before they get to the DataFormatter? If I receive multiple update events on a single topic, I just care about displaying the latest one, and can skip all the previous ones.
Two ideas:
Aggregate PropertyChangeEvents. Extend PropertyChangeSupport, overwrite public void firePropertyChange(PropertyChangeEvent evt), fire only if last event was fired more than 50ms (or whatever time seems appropriate) ago. (In fact you should overwrite every fire* method or at least the one you use in your scenario to prevent the creation of the PropertyChangeEvent.)
Drop the whole event based approached. 60.000 events per second is a quite high number. In this situation I would poll. It is a conceptual change to MVP where the presenter knows if it is in active state and should poll. With this approach you don't generate thousands of useless events; you can even present the highest possible frames per second, no matter how much data there is. Or you can set the presenter to a fixed rate, let it sleep between refreshes for a certain time, or let it adapt to other circumstances (like CPU load).
I would tend to the second approach.
It sounds like your DataGenerator doing a lot of non-GUI work on the EDT-thread. I would recommend that your DataGenerator extend SwingWorker and by that doing the work in a background thread, implemented in doInBackground. The SwingWorker could then publish intermediate results to the GUI, while you have a process method that receives the last few published chunks on the EDT and update your GUI.
The SwingWorkers process method does coalesce the published chunks, so it will not run once for every published intermediate result.
If you only care of the last result on the EDT you can use this code, that only cares about the last chunk in the list:
#Override
protected void process(List<Integer> chunks) {
// get the *last* chunk, skip the others
doSomethingWith( chunks.get(chunks.size() - 1) );
}
Read more on SwingWorker: Tasks that Have Interim Results.
You could use a ArrayBlockingQueue of size 1, in which you would push your data with offer() function (means if the queue is full, it does nothing)
Then create a ScheduledThreadPoolExecutor which periodically polls the queue.
This way you loose the coupling between generation and display.
Generator -> Queue -> Formatting/Display
Another possibility is to just add the listener to your generator, but instead of directly reacting to the change you just start a timer. So your listener would look like (in sort of pseudo-code since I am too lazy to fire up my IDE or look up the exact method signatures)
Timer timer = new Timer( 100, new ActionListener(){//update the UI in this listener};
public void propertyChange( PropertyChangeEvent event ){
if ( timer.isRunning() ){
timer.restart();
} else {
timer.start();
}
}
This will work unless your data generator keeps on generating data the whole time, or if you want intermediate updates as well. In that case you can just remove the timer.restart() call, or opt for any of the other suggestions in this thread (the polling mechanism, or the SwingWorker)
If you write your own small change listener that has a blocking flag and a timer, you can:
syncronized onChangeRequest() {
if (flag) {
flag = false;
startTimer();
}
}
timerEvent() {
notify all your listeners;
}
I believe there is actually an excellent blocking concurrency flag that could be used but I cannot for the life of me remember what it is called!

Categories