0

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?

RealSkeptic
  • 33,993
  • 7
  • 53
  • 79
Philip94
  • 17
  • 6
  • 2
    Is `buffer` a thread-safe type? – RealSkeptic Sep 08 '16 at 12:23
  • OT, but `if ((String) object[1] == "red")` [will not work](http://stackoverflow.com/questions/513832/how-do-i-compare-strings-in-java) – James_D Sep 08 '16 at 12:25
  • @James_D In this example it will work (using string literals), but it's probably luck indeed. – assylias Sep 08 '16 at 12:25
  • @RealSkeptic No, but that is not necessary because the method in which the buffer is accessed is synchronized – Philip94 Sep 08 '16 at 12:26
  • @assylias Doesn't that depend on where the string on the left side of the `==` originates from? It doesn't necessarily get interned, right? – James_D Sep 08 '16 at 12:26
  • 1
    @Philip94 Access to the buffer certainly doesn't appear to be synchronized in the `changeColor` method you posted. – James_D Sep 08 '16 at 12:27
  • 1
    @James_D Just referring to the specific example (first line of code in the question `buffer.add(.... "red")`). Agreed with you otherwise. – assylias Sep 08 '16 at 12:27
  • Why is the conde in the screenshot different to the code in the question? – fabian Sep 08 '16 at 12:29
  • 2
    That specific method doesn't look synchronized. And if it's called from a synchronized method, what does it synchronize on? What are the methods that *modify* the buffer synchronizing on? Please [edit] and add the information. – RealSkeptic Sep 08 '16 at 12:29
  • ok thx problem solved because buffer was not really synchronized :) – Philip94 Sep 08 '16 at 12:42
  • 1
    Instead of trying to manage synchronization yourself, it's always better to use library classes that do that for you; e.g. using a `BlockingQueue` or `ConcurrentLinkedQueue` instead of a `List` here would both simplify your code (your business logic would be less cluttered with details of the concurrency requirements) and reduce the scope for errors such as the one you encountered. – James_D Sep 08 '16 at 12:51

1 Answers1

1

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

Steve
  • 981
  • 1
  • 8
  • 22