JavaFx new Thread with same Task as input - java

I am working on a JavaFX desktop application and I have one button that should read from the memory of an embedded device and print that into a JSON. I have implemented a Task that does that, and this Task is passed as argument to a new thread in the button event handler. The problem is, this only works once. After that, even though new threads are generated on button click, the call() method of the Task is never called again. Here is the code:
The Task definition:
Task readValDaemon = new Task<Void>() {
#Override
public Void call() {
//This functions reads from memory and writes the JSON
readDataHI(connection,commandListHI,statusHI);
return null;
}
};
The Thread creation:
readData.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
Thread readValThread = new Thread(readValDaemon);
readValThread.setDaemon(true);
readValThread.start();
}
});

As observed in other answers, a Task is an implementation of FutureTask. From the Task documentation:
As with FutureTask, a Task is a one-shot class and cannot be reused. See Service for a reusable Worker.
So you cannot reuse a task. Second and subsequent attempts to run it will just silently fail.
You could just create a new task directly every time:
private Task<Void> createReadValTask() {
return new Task<Void>() {
#Override
public Void call() {
//This functions reads from memory and writes the JSON
readDataHI(connection,commandListHI,statusHI);
return null;
}
};
}
and then do
readData.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
Thread readValThread = new Thread(createReadValTask());
readValThread.setDaemon(true);
readValThread.start();
}
});
You could also consider using a Service, which is designed for reuse. It basically encapsulates the "create a new task every time" functionality, but adds in a lot of useful UI callbacks. A Service also manages a thread pool for you (via an Executor), so you no longer need to worry that you may be creating too many thread. (The Executor can also be specified, if you want to control it.)
So, e.g.:
Service<Void> readValDaemon = new Service<Void>() {
#Override
protected Task<Void> createTask() {
return new Task<Void>() {
#Override
public Void call() {
//This functions reads from memory and writes the JSON
readDataHI(connection,commandListHI,statusHI);
return null;
}
};
}
};
and then
readData.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
readValThread.restart();
}
});
If the mouse is clicked while the service is already running, this will automatically cancel the already running task, and restart a new one. You could add in checks if you wanted, or bind the disable state of readData to the state of the Service, if you wanted.

Task is kind of the wrong tool for this. It's very purposefully only designed to run once because it's a kind of future. It stores the result (in your case null) as a kind of memoization to avoid doing expensive operations more times than is necessary. So Task is best suited for situations where an expensive computation must be done just once, and usually you would want a result from it at some point down the line.
The documentation for Task is very thorough so I would give that a read.
In your case, just use a plain Runnable. You can use a lambda expression:
readData.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event)
{
Thread readValThread = new Thread(() -> readDataHI(a, b, c));
readValThread.setDaemon(true);
readValThread.start();
}
});
As an aside, creating threads manually isn't considered very good practice in modern Java. Strongly consider an ExecutorService instead.

Related

Threads in JavaFX: do threads need to be killed?

I'm writing an application using JavaFX and my understanding is that, while the UI runs in a thread, all other non-UI operations must run in another. So far, all examples I've found are variations of the following:
myButton.setOnAction(new EventHandler<ActionEvent>(){
#Override
public void handle(ActionEvent a) {
// Some UI operations
new Thread() {
public void run() {
// Some non-UI operations
Platform.runLater(new Runnable() {
public void run() {
// Some operations to update the UI
}
});
}
}.start();
}
});
My question is: do you need to somehow kill the thread in order to release its resources? In the examples I've never nobody seems to use Thread.join or any other similar method.
Also, would it be advisable to use setDaemon like this?
myButton.setOnAction(new EventHandler<ActionEvent>(){
#Override
public void handle(ActionEvent a) {
// Some UI operations
final Thread child = new Thread() {
public void run() {
// Some non-UI operations
Platform.runLater(new Runnable() {
public void run() {
// Some operations to update the UI
}
});
}
};
child.setDaemon(true);
child.start();
}
});
Note:
According to this thread (JavaFX multithreading - joining threads won't update the UI) Thread.join must not be used, but it doesn't seem to address the question of what happens to the threads that are no longer needed or how to kill them.
Threads will age out when there is nothing scheduled for them. However, it is not a good practice to depend on that, as it can take up resources.
The better approach is to use an ExecutorService, such as described in the documentation. A ThreadPoolExecutor can run one or more threads. You can use the same executor to keep submitting runnable tasks, and they will be executed on the threads that it manages. The documentation gives examples on how to shut down the executor service at the end of your application. If you are confident that you have no outstanding tasks being executed, you can issue shutdownNow() to immediately clean up all the threads.

Attempting to run 2 AsyncTasks in parallel, but they appear to block each other

I'm working on an app that sends sensor data and receives connection data via UDP. Originally, the app only sent data, and only used 1 AsyncTask. However, the app is now needs to receive data due to a protocol change, and this needs to be handled on its own thread and trigger UI updates, thus, I've created a new AsyncTask for it
PROBLEM:
When run independently, the AsyncTasks execute perfectly. However, when I run them at the same time, one eventually completely blocks the other.
WHAT IVE TRIED:
Originally, I was using the standard .execute() to start my AsyncTasks. After reading similar questions, I've implemented the function below instead, hoping to force parallel execution:
void startAsyncTask(AsyncTask<Void, Void, Void> asyncTask) {
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
else
asyncTask.execute();
I expected this to work, however, it did not. The two tasks still block each other.
What could potentially be causing this? My guesses are potentially a limited pool size, since the two tasks are firing at a very frequent rate (perhaps one task eventually dominates the pool, leaving no free threads), but then again, I'm not entirely sure.
ADDITIONAL CODE:
Here is how I set up the timers to execute my asynctasks:
timer = new Timer();
task = new TimerTask() {
#Override
public void run() {
handler.post(new Runnable() {
public void run() {
if (dataClient.getStatus() == AsyncTask.Status.FINISHED) {
dataClient = new udpClient();
}
if (dataClient.getStatus() != AsyncTask.Status.RUNNING) {
if(sensorValues != null) {
if(isUdpEnabled)
startAsyncTask(dataClient);
}
}
}
});
}
};
timer.schedule(task, 0, 25);
timer2 = new Timer();
task2 = new TimerTask() {
#Override
public void run() {
handler2.post(new Runnable() {
public void run() {
if (broadcastClient.getStatus() == AsyncTask.Status.FINISHED) {
broadcastClient = new udpBroadcastClient();
}
if (broadcastClient.getStatus() != AsyncTask.Status.RUNNING) {
Log.d("broadcast test", "Timer fire");
startAsyncTask(broadcastClient);
Log.d("broadcast test", "After execute line reached");
}
}
});
}
};
timer2.schedule(task2, 0, 50);
The actual work of both threads are both posted to the same handler meaning it will cause them to run one after another. If you put a debugging statement before the handler.post you'll see that they both hit that section and then sequential execution begins. Can't you just use new Thread(){...}.start()?

Starting/Calling the same thread multiple times Java Android

I need to call the same thread multiple times in my app. Using my original code, the first time is can be executed just fine. But the second time it crashes - I then learned that each thread shall only be executed not more than one time.
My original piece of code:
View.OnClickListener myClickListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
mythread.start();
}
};
Thread mythread = new Thread(){
#Override
public void run() {
runOnUiThread(new Runnable() {
public void run() {
demoBt.setText("Running...");
}
});
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
runOnUiThread(new Runnable() {
public void run() {
demoBt.setText("Finished...");
}
});
}
};
So as I said, it crashes if I try to run it for the second time. So I tried modifying it like:
View.OnClickListener myClickListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
test();
}
};
private void test(){
Thread mythread = new Thread(){
#Override
public void run() {
runOnUiThread(new Runnable() {
public void run() {
demoBt.setText("Running...");
}
});
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
runOnUiThread(new Runnable() {
public void run() {
demoBt.setText("Finished...");
}
});
}
};
mythread.start();
}
It works very good; but my question is that whether this is the correct way to do this action or there is a more optimal way to do this?
Also, is it an acceptable thing to call a thread from insider of another thread? (like the way I put stuff on UI Thread inside the new thread of mine)
EDIT:
This is just an example. For my actual code I have heavy math-based simulation to be done which takes 10sec to be done. Based on the results that will be shown to the user , they may want to change their input parameters and let the simulation run again. This will happen several times.
In addition to the other good answers about using AsyncTask or runOnUiThread(), you could define a private member as a Runnable, like this:
private Runnable mytask = new Runnable() {
#Override
public void run() {
runOnUiThread(new Runnable() {
public void run() {
demoBt.setText("Running...");
}
});
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
runOnUiThread(new Runnable() {
public void run() {
demoBt.setText("Finished...");
}
});
}
};
Then, whenever you want to run it, do
new Thread(mytask).start();
There is nothing bad with that but I think a better way would be using AsyncTask. It is exactly designed for this cases.
You can use AsyncTask multiple times just creating a new one like this new MyAsyncTask().execute(""); (source from here)
Also, is it an acceptable thing to call a thread from insider of another thread? (like the way I put stuff on UI Thread inside the new thread of mine)
runOnUiThread exists solely for that purpose. But there are usually much better ways (e.g. AsyncTask) so using this method is probably a bad idea.
my question is that whether this is the correct way to do this action or there is a more optimal way to do this?
You should not use a thread just to schedule future tasks. They are useful to execute something in parallel to the main thread but add lots of potential errors (try rotating the screen between it prints running..finished, could crash)
I would use a CountDownTimer in your case.
Or a Handler, examples e.g. here: Schedule task in android
From the provided code I assume that you want to perform an UI operation before and after your long mathematical computation. In such as #Andres suggested, AsyncTask is your best buy. It provides method onPreExecute, onPostExecute which runs on UI thread, and thus no need for explicitly calling runOnUiThread.
Key concepts :
You can't start an already started thread. This will return in an IllegalStateException. If you need to perform same task again, you should create a new instance.
If you find yourself creating several instances of a thread (even AsyncTask), since you need to run same task again and again, I would suggest you to use Thread Pool or simple Java Executor Service. Create a singleThread or may be pool and post your runnable onto executorService and it will take care of the rest.
Inter-Thread or Inter-Process communication is quite common requirement.

How to make this search in a new thread

I have search as you type functionality although it searches very fast and I can't notice it even with no multithreading I still want to know how would I use multithreading on this
search.textProperty().addListener(new ChangeListener<String>() {
#Override
public void changed(ObservableValue<? extends String> observableValue, String s, String s2) {
manager.searchString(s2);
listView.getItems().setAll(manager.getList());
}
});
So basically there is a TextField that when its text is changed I go and call a search method in object manager which puts its search result in an array when it finishes.
Then the ListView should update its data to this new array when it finishes.
How can I make the search on one thread and when it finishes it update the list data?!
I believe I can't just call the list function from other thread because GUI stuff should be called from only one thread.
To do this efficiently in a different thread is not as simple as it sounds.
You don't want to create and execute a new thread every time a key is pressed because:
There is system overhead for thread creation which would make that an extremely intensive process
There's no guarantee that the threads will execute and complete in the order they are created, so you may get an earlier thread finishing after a subsequent one and consequentially updating the list with invalid entries.
You could use a single-thread executor service (which keeps one thread alive and uses it to execute Runnables passed into it in order), which would be more efficient, but you'd need to remember to shut it down when your text field is destroyed (if you do ever destroy your text field). Something along these lines:
// first of all, at the class level (assuming listView and manager are both class-level variables, preferably final ones, too):
// An INNER class implementing Runnable which will carry out the searching
private class Searcher implements Runnable {
private volatile boolean cancelled = false;
private final String searchTerm;
Searcher(String searchTerm) {
this.searchTerm = searchTerm;
}
public void cancel() {
cancelled = true;
}
#Override
public void run() {
// remember that there's no guarantee that this will execute before the NEXT keypress, so we add a check to ensure that we still want to perform the search when it gets executed:
if (!cancelled) {
manager.searchString(searchTerm);
Platform.runLater(listViewUpdater); // listViewUpdater is defined below
}
}
}
// a Runnable to actually update the GUI after a seach has been performed
private Runnable listViewUpdater = new Runnable(){
#Override
public void run() {
listView.getItems().setAll(manager.getList());
}
}
private ExecutorService executor = Executors.newSingleThreadExecutor();
private Searcher lastSearcher = null;
// ... then, in the method which sets up the GUI
search.textProperty().addListener(new ChangeListener<String>() {
#Override
public void changed(ObservableValue<? extends String> observableValue, String s, String s2) {
if (lastSearcher != null) {
lastSearcher.cancel(); // prevents lastSearcher from running if it hasn't done so already
}
lastSearcher = new Searcher(s2);
executor.submit(lastSearcher);
}
});
The downside is you are creating a new object every time the value changes, but that isn't nearly as bad as creating a new Thread every time.

Wait for thread to finish in Java

I have some code which executes a download in a separate thread, created so that the JFrame GUI will continue to update during the download. But, the purpose is completely defeated when I use Thread.join(), as it causes the GUI to stop updating. I need a way to wait for the thread to finish and still update the GUI.
You can have the task that does the download also fire an event to the GUI.
For example:
Runnable task = new Runnable() {
public void run() {
// do your download
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// call some method to tell the GUI that the download finished.
}
});
}
};
and then to run it, either use an Executor (preferred method) or a raw thread:
executor.execute(task);
or
new Thread(task).start();
As pointed out in the comments, you'd generally use a SwingWorker to do this kind of thing but you can also do the manual approach outlined above.
SwingWorker provides a doInBackground method where you would stick your download logic in, a done method where you would stick in code to notify the GUI that the download finished and a get method to get the result of doInBackground (if there was one).
E.g.,
class Downloader extends SwingWorker<Object, Object> {
#Override
public Object doInBackground() {
return doDownload();
}
#Override
protected void done() {
try {
frame.downloadDone(get());
} catch (Exception ignore) {
}
}
}
(new Downloader()).execute();

Categories