JavaFX SwingWorker Equivalent? - java

Is there a JavaFX equivalent to the Java SwingWorker class?
I am aware of the JavaFX Task but with that you can only publish String messages or a progress. I just want to call a method in the GUI thread like I would have done with the SwingWorker (by publishing messages of an arbitrary type).
Heres is an example of what I mean:
class PrimeNumbersTask extends
SwingWorker<List<Integer>, Integer> {
PrimeNumbersTask(JTextArea textArea, int numbersToFind) {
//initialize
}
#Override
public List<Integer> doInBackground() {
while (! enough && ! isCancelled()) {
number = nextPrimeNumber();
publish(number);
setProgress(100 * numbers.size() / numbersToFind);
}
}
return numbers;
}
#Override
protected void process(List<Integer> chunks) {
for (int number : chunks) {
textArea.append(number + "\n"); // HERE: execute in GUI thread
}
}
}
Solution
Thank you very much for your answers. The solution I was searching for, is to use Platform.runLater(Runnable guiUpdater).

I would rewrite your SwingWorker as follows:
class PrimeNumbersTask extends Task<List<Integer>> {
PrimeNumbersTask(TextArea textArea, int numbersToFind) {
// initialize
}
#Override
protected List<Integer> call() throws Exception {
while (!enough && !isCancelled()) {
number = nextPrimeNumber();
updateMessage(Integer.toString(number));
updateProgress(numbers.size(), numbersToFind);
}
return numbers;
}
}
Usage:
TextArea textArea = new TextArea();
PrimeNumbersTask task = new PrimeNumbersTask(numbersToFind);
task.messageProperty().addListener((w, o, n)->textArea.appendText(n + "\n"));
new Thread(task).start(); // which would actually start task on a new thread
Explanation:
Yes, we do not have a publish() method as the SwingWorker does in JavaFX, but in your case using the updateMessage() is sufficient, as we can register a listener to this property and append a new line every time the message is updated.
If this is not enough, you can always use Platform.runLater() to schedule GUI updates. If you are doing too many GUI updates and the GUI Thread is being slowed down, you can use the following idiom: Throttling javafx gui updates

Apart from the updateMessage method where you can only pass strings, there is the updateValue method where you can pass a whole object, so I believe you can use that in a similar manner. This approach is described in the "A Task Which Returns Partial Results" section of the Task documentation. Another approach is the Platform.runLater() approach mentioned also in other answer.
Note that an important difference between these approaches, is that the first one is coalescing the results, which means that for multiple frequent updateValue calls some may be omitted in order to protect flooding the FX thread.
On the other hand, the Platform.runLater approach will send all the interim results, but due to the danger of flooding the FX thread if you have high frequency updates, some additional effort may be needed to manually avoid it like #eckig suggested in his answer which points to Throttling javafx gui updates

Don't ever use SwingWorker. This piece of code in the SwingWorker.java source should be enough of an argument to not use it:
private static final int MAX_WORKER_THREADS = 10;
Instead get yourself familiar with Executor and the services that come along with it.
It has nothing to do with JavaFX, it's just plain Java. However, your question was related to JavaFX. Here's an example about how to Update UI in JavaFX Application Thread using Platform.runLater().

Related

Swing Worker threads stop executing code unexpectedly

I am trying to create a platform for testing mutual exclusion algorithms using Swing. My intent is to display servers and messages being sent between them in the GUI. I also want to display a critical section which shows which servers are currently accessing it. I am using a threadpool that executes SwingWorker threads to deploy the servers which load a user selected mutex algorithm.
The program runs as expected until I try to implement the message displays. To display an arrow for each message I've extended SwingWorker, UIArrowThread, to add a JLabel that draws an arrow from the source server to the target. This thread waits for 1 second before removing the JLabel. This seems to be working fine when I explicitly create one or more of these messages(I've also created a test platform where I can create specific messages).
The problem comes when I try to integrate this SwingWorker thread into the program. When the algorithm is started, each server attempts to access the critical section and sends its requests to each of the other servers. This should invoke UIArrowThread but it appears that only some servers actually create the thread.
public void sendMsg(int destId, Object ... objects) {
comm.sendMsg(destId, objects);
try{
UIArrowThread a = new UIArrowThread(AlgorithmSimulatorUI.jlp,
objects[0].toString(),
comm.getMyId(),
destId);
AlgorithmSimulatorUI.threadPool.execute(a);
} catch (Exception exc){
System.err.println(exc);
}
}
Some of the servers just seem to stop executing just before instantiating UIArrowThread and ends up creating a deadlock. Any servers that do make it passed that point work normal and the GUI displays as it should be. I have testing with logging just before UIArrowThread is called and in its constructor. The threads that look like they stop executing never make the log call in the constructor. I'm pretty stumped on why this would be happening.
public class UIArrowThread extends SwingWorker<Integer, String>{
JLayeredPane jlp;
String type;
int source;
int target;
Point start;
Point end;
Point[] points;
int quadrant;
public UIArrowThread(JLayeredPane jlp, String msg_type, int source,
int target){
this.jlp = jlp;
this.type = msg_type;
this.source = source;
this.target = target;
this.points = getPoints();
this.start = points[0];
this.end = points[1];
}
#Override
protected Integer doInBackground(){
Point lblPoint = getLabelCoordinates(points);
ArrowLabel arrow = new ArrowLabel(type, 1, 2, jlp, points, quadrant);
if (quadrant < 5){
arrow.setBounds(lblPoint.x, lblPoint.y, abs(start.x - end.x),
abs(start.y - end.y));
} else if (quadrant < 7){
arrow.setBounds(lblPoint.x, lblPoint.y, 100, abs(start.y - end.y));
} else {
arrow.setBounds(lblPoint.x, lblPoint.y, abs(start.x - end.x), 100);
}
jlp.add(arrow);
String openHTML = "<html><font color='red',size=12>";
String closeHTML = "</font></html>";
arrow.setText(openHTML + type + closeHTML);
arrow.setHorizontalTextPosition(JLabel.CENTER);
arrow.setVerticalTextPosition(JLabel.CENTER);
jlp.repaint();
try{
Thread.sleep(arrow.lifespan);
} catch (Exception exc){
System.err.println(exc);
} finally {
jlp.remove(arrow);
}
jlp.repaint();
return 1;
}
I've added what I feel would be the relevant part of code for this problem. As mentioned above, if I remove the UIArrowThread, the program will run correctly.
I tried a few more approaches that still produce the same results including doing the work in process() instead of doInBackground(), and having the ArrowLabel remove itself from the GUI instead of UIArrowThread doing the removal.
Update:
I was able to get the UI working as intended but still not really sure what the original issue is. The program has a messaging queue that displays the messages from servers in a textPane so I figured I'd update the UI with the arrow labels here. It was not neccessary to alter any of the existing code for ArrowLabel or UIArrowThread.
Your fragment suggests that you are updating a Swing component, ArrowLabel, in the doInBackground() method of a SwingWorker. This violates the Swing single-thread rule. Instead, query the servers in the background, publish() interim results, and process() them on the EDT, as shown in the examples examined here. The exact formulation of "the type used for carrying out intermediate results by this SwingWorker's publish and process methods" will depend on your use case. As a concrete example, this TableSwingWorker extends SwingWorker<MyTableModel, RowData>, publishing instances of RowData used to update a TableModel

In a Java 7+ ForkJoinPool, is it possible to cancel a task and all subtasks?

My program searches for a solution (any solution) to a problem through a divide-and-conquer approach, implemented using recursion and RecursiveTasks's: I fork a task for the first branch of the division, then recurse into the second branch: if the second branch has found a solution, then I cancel the first branch, otherwise I wait for its result.
This is perhaps not optimal. One approach would be for any of the launched tasks to throw an exception if a solution is found. But then, how would I cancel all the launched tasks? Does cancelling a task also cancel all sub-tasks?
You can use the simple approach with task manager. For example:
public class TaskManager<T> {
private List<ForkJoinTask<T>> tasks;
public TaskManager() {
tasks = new ArrayList<>();
}
public void addTask(ForkJoinTask<T> task) {
tasks.add(task);
}
public void cancelAllExcludeTask(ForkJoinTask<Integer> cancelTask) {
for (ForkJoinTask<T> task : tasks) {
if (task != cancelTask) {
task.cancel(true);
}
}
}
public void cancelTask(ForkJoinTask<Integer> cancelTask) {
for (ForkJoinTask<T> task : tasks) {
if (task == cancelTask) {
task.cancel(true);
}
}
}
}
And the task:
public class YourTask extends RecursiveTask<Integer> {
private TaskManager<Integer> taskManager;
#Override
protected Integer compute() {
// stuff and fork
newTask.fork();
// do not forget to save in managers list
taskManager.addTask(newTask);
// another logic
// if current task should be cancelled
taskManager.cancelTasks(this);
// or if you have decided to cancel all other tasks
taskManager.cancelAllExcludeTask(this);
}
}
The framework cannot cancel a task for the same reason you cannot cancel a thread. See the documentation on Thread.stop() for all the reasons. What locks could the task be holding? What outside resources could it have linkage to? All the same Thread.stop() reasons apply to tasks as well (after all, tasks run under threads.) You need to tell the task to stop just like you tell a thread to stop.
I manage another fork/join project that uses the scatter-gather technique. The way I do a cancel, or short-circuit, is that every task I create is passed an object (PassObject) that has a
protected volatile boolean stop_now = false;
and a method for stopping the task
protected void stopNow() {stop_now = true; }
Each task periodically checks the stop_now and when true it gracefully ends the task.
Unfortunately, the stop_now needs to be volatile since another thread is going to set it. This can add significant overhead if you check it frequently.
How to set this field in another task gets a little tricky. Each task I create also contains a reference to the array of references to every other task
int nbr_tasks = nbr_elements / threshold;
// this holds the common class passed to each task
PassObject[] passList = new PassObject[nbr_tasks];
for (int i = 0; i < nbr_tasks; i++)
passList[i] = new PassObject( passList,… other parms);
Once the list is formed I fork() each object in passList. Each PassObject contains a reference to the array, passList, which contains a reference to every object that is passed to each task. Therefore, every task knows about every other task and when one task want to cancel the others it simply calls the cancelOthers method with a reference to the passList.
private void cancelOthers (PassObject[] others) {
// tell all tasks to stop
for (int i = 0, max = others.length; i < max; i++)
others[i].stopNow();
If you’re using Java8 then you can do a form of scatter-gather with the CountedCompler class instead of the RecusiveTask. For Java7 or if you still want to use RecursiveTask, then the first task in the recursion needs to create an AtomicBoolean field (AtomicBoolean stop_now = new AtomicBoolean(false);) and include a reference to this field in every new RecursiveTask it creates. With recursion, you don’t know how many levels of tasks you’ll need in the beginning.
Again, you’ll need to check for a true in the boolean periodically in your code and when true, end the task gracefully.
The above is just a hint of how you can do a cancel. Every application is different. What I do works for my application – but the logic is the same. You need something common in every task that a task can set and every other task can see.
I'd add more code but the code insert only is taking one line at a time and it isn't practical.

Java: Getting ExecutorService to produce repeatable behavior?

I have been trying to parallelize a portion of a method within my code (as shown in the Example class's function_to_parallelize(...) method). I have examined the executor framework and found that Futures & Callables can be used to create several worker threads that will ultimately return values. However, the online examples often shown with the executor framework are very simple and none of them appear to suffer my particular case of requiring methods in the class that contains that bit of code I'm trying to parallelize. As per one Stackoverflow thread, I've managed to write an external class that implements Callable called Solver that implements that method call() and set up the executor framework as shown in the method function_to_parallelize(...). Some of the computation that would occur in each worker thread requires methods *subroutine_A(...)* that operate on the data members of the Example class (and further, some of these subroutines make use of random numbers for various sampling functions).
My issue is while my program executes and produces results (sometimes accurate, sometimes not), every time I run it the results of the combined computation of the various worker threads is different. I figured it must be a shared memory problem, so I input into the Solver constructor copies of every data member of the Example class, including the utility that contained the Random rng. Further, I copied the subroutines that I require even directly into the Solver class (even though it's able to call those methods from Example without this). Why would I be getting different values each time? Is there something I need to implement, such as locking mechanisms or synchronization?
Alternatively, is there a simpler way to inject some parallelization into that method? Rewriting the "Example" class or drastically changing my class structuring is not an option as I need it in its current form for a variety of other aspects of my software/system.
Below is my code vignette (well, it's an incredibly abstracted/reduced form so as to show you basic structure and the target area, even if it's a bit longer than usual vignettes):
public class Tools{
Random rng;
public Tools(Random rng){
this.rng = rng;
}...
}
public class Solver implements Callable<Tuple>{
public Tools toolkit;
public Item W;
public Item v;
Item input;
double param;
public Solver(Item input, double param, Item W, Item v, Tools toolkit){
this.input = input;
this.param = param;
//...so on & so forth for rest of arguments
}
public Item call() throws Exception {
//does computation that utilizes the data members W, v
//and calls some methods housed in the "toolkit" object
}
public Item subroutine_A(Item in){....}
public Item subroutine_B(Item in){....}
}
public class Example{
private static final int NTHREDS = 4;
public Tools toolkit;
public Item W;
public Item v;
public Example(...,Tools toolkit...){
this.toolkit = toolkit; ...
}
public Item subroutine_A(Item in){
// some of its internal computation involves sampling & random # generation using
// a call to toolkit, which houses functions that use the initialize Random rng
...
}
public Item subroutine_B(Item in){....}
public void function_to_parallelize(Item input, double param,...){
ExecutorService executor = Executors.newFixedThreadPool(NTHREDS);
List<Future<Tuple>> list = new ArrayList<Future<Tuple>>();
while(some_stopping_condition){
// extract subset of input and feed into Solver constructor below
Callable<Tuple> worker = new Solver(input, param, W, v, toolkit);
Future<Tuple> submit = executor.submit(worker);
list.add(submit);
}
for(Future<Tuple> future : list){
try {
Item out = future.get();
// update W via some operation using "out" (like multiplying matrices for example)
}catch(InterruptedException e) {
e.printStackTrace();
}catch(ExecutionException e) {
e.printStackTrace();
}
}
executor.shutdown(); // properly terminate the threadpool
}
}
ADDENDUM: While flob's answer below did address a problem with my vignette/code (you should make sure that you are setting your code up to wait for all threads to catch up with .await()), the issue did not go away after I made this correction. It turns out that the problem lies in how Random works with threads. In essence, the threads are scheduled in various orders (via the OS/scheduler) and hence will not repeat the order in which they are executed every run of the program to ensure that a purely deterministic result is obtained. I examined the thread-safe version of Random (and used it to gain a bit more efficiency) but alas it does not allow you to set the seed. However, I highly recommend those who are looking to incorporate random computations within their thread workers to use this as the RNG for multi-threaded work.
The problem I see is you don't wait for all the tasks to finish before updating W and because of that some of the Callable instances will get the updated W instead of the one you were expecting
At this point W is updated even if not all tasks have finished
Blockquote
// update W via some operation using "out" (like multiplying matrices for example)
The tasks that are not finished will take the W updated above instead the one you expect
A quick solution (if you know how many Solver tasks you'll have) would be to use a CountDownLatch in order to see when all the tasks have finished:
public void function_to_parallelize(Item input, double param,...){
ExecutorService executor = Executors.newFixedThreadPool(NTHREDS);
List<Future<Tuple>> list = new ArrayList<Future<Tuple>>();
CountDownLatch latch = new CountDownLatch(<number_of_tasks_created_in_next_loop>);
while(some_stopping_condition){
// extract subset of input and feed into Solver constructor below
Callable<Tuple> worker = new Solver(input, param, W, v, toolkit,latch);
Future<Tuple> submit = executor.submit(worker);
list.add(submit);
}
latch.await();
for(Future<Tuple> future : list){
try {
Item out = future.get();
// update W via some operation using "out" (like multiplying matrices for example)
}catch(InterruptedException e) {
e.printStackTrace();
}catch(ExecutionException e) {
e.printStackTrace();
}
}
executor.shutdown(); // properly terminate the threadpool
}
then in the Solver class you have to decrement the latch when call method ends:
public Item call() throws Exception {
//does computation that utilizes the data members W, v
//and calls some methods housed in the "toolkit" object
latch.countDown();
}

Synchronizing Hashmap in Threading

I am facing some issues with synchronizing my idMap. This map is being used in two run() methods which are run concurrently. In the 1st run() method i'm simply mapping event id value) to response id (key). in the 2nd run() method I wish to obtain the event id (value) with that same response id (key). However, at times some event id is there and at times they can't be obtained. The program compiles just fine, but i'm no expert at threading and i believe threading is causing this idMap to be out of sync. My question is simply, how can I make idMap work smoothly and obtain the event ids as I intend to?
ConcurrentHashMap<String, String> idMap = new ConcurrentHashMap<String, String>();
ConcurrentHashMap<String, ExecutorService> executors = new ConcurrentHashMap<String, ExecutorService>();
private final class ResponderTask implements Runnable {
private ResponderTask(Event event) {
this.event = event;
}
// 1st run()
public void run() {
idMap.put(response.getId(), event.getId());
}
}//end ResponderTask
private final class QuoteTask implements Runnable {
//constructor
//2nd run()
public void run() {
IdMap.get(response.getId());
}
}//end QuoteTask
public void onResponse(final Response response) {
ExecutorService quoteExecutor = executors.get(response.getId());
if (quoteExecutor == null) {
quoteExecutor = Executors.newSingleThreadExecutor();
executors.put(event.getId(), quoteExecutor);
}
quoteExecutor.execute(new ResponderTask(event));
}
However, at times some event id is there and at times they can't be obtained. The program compiles just fine, but i'm no expert at threading and i believe threading is causing this idMap to be out of sync.
idMap is a ConcurrentHashMap which is properly synchronized and highly used and tested by many folks. If the id is not in the map when you look it up then it has not been put in there. If you explain a bit more about your code we may be able to find your problem.
For example, I don't see where the response object originates from. Is it possible that the ResponseTask is processing a different response then you expect? Is response and event supposed to be the same argument?
My question is simply, how can I make idMap work smoothly and obtain the event ids as I intend to?
It's a little hard to figure out what the proper operation of the program is supposed to be. If you are looking for the other thread to get the event you could use a BlockingQueue. Then your other thread can do a queue.take() which will wait until there is an event to process. But I'm not sure what the goal is here.
One thing that is very strange is the use of a map of ExecutorService. Do you really need multiple of them? I suspect that you really should use a single Executors.newCachedThreadPool(). Maybe, however, you want a single thread working on all requests with the same id in which case your code should work. I assume you are doing something like the following when you want to shutdown you application:
for (ExecutorService executor : executors.values()) {
executor.shutdown();
}

Java Threading Tutorial Type Question

I am fairly naive when it comes to the world of Java Threading and Concurrency. I am currently trying to learn. I made a simple example to try to figure out how concurrency works.
Here is my code:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadedService {
private ExecutorService exec;
/**
* #param delegate
* #param poolSize
*/
public ThreadedService(int poolSize) {
if (poolSize < 1) {
this.exec = Executors.newCachedThreadPool();
} else {
this.exec = Executors.newFixedThreadPool(poolSize);
}
}
public void add(final String str) {
exec.execute(new Runnable() {
public void run() {
System.out.println(str);
}
});
}
public static void main(String args[]) {
ThreadedService t = new ThreadedService(25);
for (int i = 0; i < 100; i++) {
t.add("ADD: " + i);
}
}
}
What do I need to do to make the code print out the numbers 0-99 in sequential order?
Thread pools are usually used for operations which do not need synchronization or are highly parallel.
Printing the numbers 0-99 sequentially is not a concurrent problem and requires threads to be synchronized to avoid printing out of order.
I recommend taking a look at the Java concurrency lesson to get an idea of concurrency in Java.
The idea of threads is not to do things sequentially.
You will need some shared state to coordinate. In the example, adding instance fields to your outer class will work in this example. Remove the parameter from add. Add a lock object and a counter. Grab the lock, increment print the number, increment the number, release the number.
The simplest solution to your problem is to use a ThreadPool size of 1. However, this isn't really the kind of problem one would use threads to solve.
To expand, if you create your executor with:
this.exec = Executors.newSingleThreadExecutor();
then your threads will all be scheduled and executed in the order they were submitted for execution. There are a few scenarios where this is a logical thing to do, but in most cases Threads are the wrong tool to use to solve this problem.
This kind of thing makes sense to do when you need to execute the task in a different thread -- perhaps it takes a long time to execute and you don't want to block a GUI thread -- but you don't need or don't want the submitted tasks to run at the same time.
The problem is by definition not suited to threads. Threads are run independently and there isn't really a way to predict which thread is run first.
If you want to change your code to run sequentially, change add to:
public void add(final String str) {
System.out.println(str);
}
You are not using threads (not your own at least) and everything happens sequentially.

Categories

Resources