• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Tim Cooke
  • Campbell Ritchie
  • Paul Clapham
  • Ron McLeod
  • Liutauras Vilda
Sheriffs:
  • Jeanne Boyarsky
  • Rob Spoor
  • Bear Bibeault
Saloon Keepers:
  • Jesse Silverman
  • Tim Moores
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
Bartenders:
  • Piet Souris
  • Al Hobbs
  • salvin francis

Rapidly updating GUI elements in a multi-threaded app

 
Rancher
Posts: 259
13
Eclipse IDE C++ Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
hello, i just started to teach myself about making a multi-threaded app. I have a GUI and i learned that you must update the GUI elements with Platform.runLater or the app will freeze/crash because only the "application thread" is allowed to touch the GUI. my GUI uses javafx but if you don't know anything about javafx you can probably still help me because it's similar to swing.

what i am doing is calling the label.setText() method from a Platform.runLater each time a variable changes. i have about a dozen values all changing very rapidly, i think maybe it will give better performance to do it differently? because i am spamming the application thread with updates on labels and listviews full of sorted lists. is it possible to use binding or an observable so that i don't have to keep setting these ui elements using Platform.runLater?

will a label's text or a listview automatically update as soon as i change the value on a variable inside my worker thread, by using binding or an observable? or what's the correct way to do this. thanks.
 
Saloon Keeper
Posts: 13398
298
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
What labels are you changing and in response to what? Do you have reason to believe that it won't be responsive enough?
 
S Fox
Rancher
Posts: 259
13
Eclipse IDE C++ Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
my app takes an encoded message and decodes it without knowing the key. it works very good even with just one thread. it uses data analysis techniques so it's not trying every single key in a brute force style, but there is still a lot of data getting processed and a lot of keys being tested. its very computationally expensive. this is why it will benefit from being multi-threaded. right now i have just a single thread for doing the work, and the application thread for the gui. but i will eventually break the work down into individual tasks to try and improve the performance or spawn multiple instances of the class one on each thread.

i want to show what my program is doing in realtime on the gui to show me the value of all the variables related to the tasks, in every thread. my cpu has 8 threads, one is reserved for the application thread. so for example if i spawn 7 worker threads to try 7 decode keys at a time, i want to show those 7 keys on the gui as they are being tried. these results from all the worker threads can get put into a static hashmap, i will use a lock to make sure only one thread can write to it at a time. showing me all the values will help me with bug-testing the app, because i am afraid of data corruption once i begin doing multi-threading.

anyways i'm still very new to java, so i think maybe there is a better way. such as with binding or observables or atomic values.
i'm trying to get as much performance as i can and prevent the gui from slowing down or freezing when i am throwing tons of data at it.

https://stackoverflow.com/questions/33146167/javafx-binding-label-with-int-value
https://stackoverflow.com/questions/22772379/updating-ui-from-different-threads-in-javafx
 
Stephan van Hulst
Saloon Keeper
Posts: 13398
298
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Just register the GUI update in the runLater() method. When the GUI thread is awake, it will coalesce multiple updates into one. When updates are performed may not coincide exactly with what your threads are really doing, but that's the nature of multithreading.

You can also simply bind your labels to observable properties. Do what you feel comfortable with and don't worry about performance.

Make sure you have no more threads running than you have processor cores, otherwise multithreading will actually lower overall performance.
 
S Fox
Rancher
Posts: 259
13
Eclipse IDE C++ Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
i tried to make my listview use an observableList but i have a problem.

if i add things to its observableList in the worker thread i get:  
Exception in thread "pool-2-thread-1" java.lang.IllegalStateException: Not on FX application thread; currentThread = pool-2-thread-1

but if i add things to its observableList in the application thread i get:
Exception in thread "JavaFX Application Thread" java.util.ConcurrentModificationException

i don't know how to make the gui update if i'm not allowed to do it on either thread!

i need a sorted list of strings based upon the Double value, so i have TreeMap like this.
private Map<Double, String> bestResults = new TreeMap<>();
controller.oBest.addAll(bestResults.values()); // add strings to the oBest observable list
 
Sheriff
Posts: 7111
184
Eclipse IDE Postgres Database VI Editor Chrome Java Ubuntu
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I think we need to see some code to figure out what's going wrong.  Can you create a SSCCE (that's a link) that demonstrates the problems?  Then post it here and UseCodeTags (that's a link too).
 
S Fox
Rancher
Posts: 259
13
Eclipse IDE C++ Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
the program is too complex to make an sscce. i have fxml to make the gui, an fxcontroller, and many classes are required to make it all run.
this isn't really a bug in the program, its more just that i don't know how i'm meant to code a multi-thread app.

i do know why it's breaking, i just don't know how to fix it.
#1 if i add things to its observableList in the worker thread, that's not allowed. i have to do it on the application thread only.

#2 if i add things to its observableList in the application thread, that's fine. but i am not allowed to iterate a Collection in my application thread while it is being appended/modified in the worker thread.
it causes a ConcurrentModificationException. the reason i need to iterate is due to needing a sorted list.

this code is what breaks it:
private Map<Double, String> bestResults = new TreeMap<>(); // this tree map sorts decoded text strings by their score, the score ranks how good they're decoded.
controller.oBest.addAll(bestResults.values()); // adds strings to the oBest observable list. causes a ConcurrentModificationException because bestResults.values() is treated as iteration
 
Marshal
Posts: 3722
533
Android Eclipse IDE TypeScript Redhat MicroProfile Quarkus Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

S Fox wrote:the program is too complex to make an sscce.


You don't need to demonstrate the whole application, just the bits are causing you grief.

S Fox wrote:#1 if i add things to its observableList in the worker thread, that's not allowed. i have to do it on the application thread only.

S Fox wrote:#2 if i add things to its observableList in the application thread, that's fine. but i am not allowed to iterate a Collection in my application thread while it is being appended/modified in the worker thread.


Can you write some small apps to demonstrate those problems?
 
Ron McLeod
Marshal
Posts: 3722
533
Android Eclipse IDE TypeScript Redhat MicroProfile Quarkus Java Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I don't really know much a lot about JavaFX, but does example code in anyway illustrate what you are trying to do - make changes to a list in a non-GUI thread, render the updated list in the GUI thread?


I'm not a JaxaFX guy, so this is probably a poor example of how JaxaFX code should be written.
 
S Fox
Rancher
Posts: 259
13
Eclipse IDE C++ Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
here's the smallest example i could make.
the listview is supposed to show a message of n chars, that has been decoded with various keys.
each result has a score showing how good it is. the results in the listview should be shown sorted.
scores are negative, so best score is the largest negative value.

(example removed, too many errors. please see the new example!)
 
S Fox
Rancher
Posts: 259
13
Eclipse IDE C++ Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
i solved the logic errors and concurrency exceptions. no more exceptions are being thrown at all.

but my app freezes-up when adding things to the observable list at full speed.
the entire cpu is only showing about 25% utilization when this happens, so it must be the application thread becoming bogged down.

i put a sleep on the worker thread to reduce the freezing, and it clearly shows that i have a data corruption problem from desync. i tried to fix it with synchronized keywords and that didn't work.
man i really hate multi threading!

i will post an updated example soon.
 
S Fox
Rancher
Posts: 259
13
Eclipse IDE C++ Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
here is my new example. please try running it, i need suggestions on how to improve the performance.

the DecodeTask is designed to run in parallel. the more of these that can run at a time the better.

i think that the mainResults hashset is the choke-point of performance. everything needs to access it.
if i made it as a ConcurrentHashMap.keySet() everything would be able to access it directly at the same time.
i tried that idea out and it works.

but i thought a normal hashset would give higher performance so i created a standard hashset that is accessed by a lock.
and i created buffers, so that if a worker thread cannot get the lock immediately it will just keep filling up a buffer.
all the worker threads should eventually get the lock and dump their buffer into mainResults.
if there is a lock-contention/starvation issue, then a buffer will never get emptied, but i think it's working correctly.

no matter what i do, it runs horribly and the GUI freezes up, the sorting being done on the listview makes it even worse.
you'll have to run it to see what i mean.



 
S Fox
Rancher
Posts: 259
13
Eclipse IDE C++ Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
i have discovered what the problem is!
line #165 and #166



both of these operations are happening so slowly that it's causing the application thread to block. freezes everything up solid.
when i comment out those 2 lines, the mainResults hashset can grow to be 20 million entries with no slowdown or problems at all.
it takes 20+ms to do the addAll, and 500+ ms to do the sorting.

i need a better way to do these things that scales well. please help?
 
Sheriff
Posts: 3837
66
Netbeans IDE Oracle Firefox Browser
  • Likes 3
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I have a few thoughts about your application:

  • Usually, when an operation is expensive, we typically move it from the GUI thread to a background thread. You could do the sort in a background thread. Some coordination between threads would be necessary.
  • The Observable list will fire a change on every change. Your application changes it very often. I'd say it would be better if you had a timer on the GUI thread you'd set to whatever refresh frequency you wanted, and the timer would read the task state from the working structure and update the GUI text.
  • Do you need the expensive sorting operation at all? Is someone going to ever look at the bottom of the list of results? Perhaps you could display only a handful of best results (top ten, top hundred, top thousand?). Keeping a list of N best results will be much less expensive than sorting an ever growing list all over and over again. For starters, as the time progresses, most of new results wouldn't even make it to the list, meaning that the frequency of the list updates would decrease over time. Plus, if you go this route, making the list of top-N result an observable list would make much more sense than it does now.
  • Are you sure you want to create a new instance of Random every time you need a random number? Typically you set up just one instance and use it to obtain all your random numbers in sequence. In this particular case, I'd create one instance of Random per worker thread.

  • Edited to add:
  • You add new results into the ol list over and over again. The list therefore grows a lot and has multiple copies of all items. That slows down things even more, of course.
  •  
    S Fox
    Rancher
    Posts: 259
    13
    Eclipse IDE C++ Java
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    thanks for your thoughts martin

    Usually, when an operation is expensive, we typically move it from the GUI thread to a background thread. You could do the sort in a background thread. Some coordination between threads would be necessary... Do you need the expensive sorting operation at all?


    i think calling foo.parallelSort from the GUI thread will automatically create a fork-join task that runs on background threads? it would then steal work from other threads to do the sorting. i don't know what sorting method it uses or if it will be the most efficient way.

    i could avoid doing any sorting at all if i insert each result into an arraylist in the correct position as soon as it's generated. the list must be locked to do this. i could use a binary search to find where to insert at. this should prevent needing to traverse the list. the insert will then shift everything down and dynamically resize the array if needed. each search/insertion will need to happen about 5k times per second per worker.

    another idea is that i can use ConcurrentSkipListMap with a comparator, to maintain the sorting.
    workers can directly dump results in there without waiting for a lock. getting a list out of this thing requires it to be slowly traversed if i have to build a new list each time i update the GUI though.

    You add new results into the ol list over and over again. The list therefore grows a lot and has multiple copies of all items.


    actually i am adding the new results to an observableset, and then adding that to the observablelist over and over, i do this to prevent duplicates but its a very slow operation. maybe i need a listchange listener to modify the observablelist instead of building a whole new list over and over.

    Are you sure you want to create a new instance of Random every time you need a random number?


    i didn't think about the cost of making this new object every time also i just noticed that there's a special randomization object for multi-thread apps. i think i should be using that one instead.
    ThreadLocalRandom

    I'd say it would be better if you had a timer on the GUI


    yesterday i did try making a service Task that updated the GUI once per second, it wasn't solving the main cause of the problem so i got rid of it, i can add it back again.
     
    Martin Vashko
    Sheriff
    Posts: 3837
    66
    Netbeans IDE Oracle Firefox Browser
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    S Fox wrote:i could avoid doing any sorting at all if i insert each result into an arraylist in the correct position as soon as it's generated. the list must be locked to do this. i could use a binary search to find where to insert at. this should prevent needing to traverse the list. the insert will then shift everything down and dynamically resize the array if needed. each search/insertion will need to happen about 5k times per second per worker.


    My solution would be to have two different data structures: one to keep the output of your computations, and another just for the data to be shown in the GUI. The first one can be kept unsorted, and when the computation finishes, it could be dumped into a file for later use (I have no idea what you plan to do with all the things your program computes). Perhaps you could use one collection per worker thread and only merge it once all is done, avoiding any synchronization between worker threads.

    The collection for the GUI would be a list that would keep N best results found so far. When a new result is produced, the worker threads would just check whether the new result makes it into the list (so it would be compared just with the last element of the list), and if it did, it could be inserted into the list (perhaps using binary search) and any items beyond the first N would be deleted. The comparison would be done on worker threads (and you could actually maintain the threshold value separately from the list and use volatile variables and/or some lightweight synchronization to access it), but inserting the new value into the list would be done on a GUI thread. Inserting new values would become quite rare fairly quickly, therefore consuming a fraction of CPU time.

    The assumption behind all this is that the user wouldn't be interested in browsing more than N intermediate results while the computation runs. I've seen some software working similarly (chess engines, for example, often show just the best line of moves found so far, despite checking thousands or millions of positions per second).

    Are you sure you want to create a new instance of Random every time you need a random number?


    i didn't think about the cost of making this new object every time


    That's only part of my concern. The other concern is that a sequence obtained this way might have inferior random properties compared to a sequence made from a stable Random instance.

    also i just noticed that there's a special randomization object for multi-thread apps. i think i should be using that one instead.
    ThreadLocalRandom


    That's a good idea. Behind the screen, ThreadLocalRandom effectively provides a separate instance of Random sequence for each thread. I guess it can be in some ways better than allocation your own Random in each thread; not sure how though.
     
    You showed up just in time for the waffles! And this tiny ad:
    Building a Better World in your Backyard by Paul Wheaton and Shawn Klassen-Koop
    https://coderanch.com/wiki/718759/books/Building-World-Backyard-Paul-Wheaton
    reply
      Bookmark Topic Watch Topic
    • New Topic