How to make this search in a new thread - java

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.

Related

How can I combine the results of multiple threads?

I am trying to perform a replace operation on the same string with multiple threads. I have created a class that will do so, given the text and a list of string arrays containing the targets and replacements:
public class ParallelReplacer implements Runnable {
private String text = "";
private List<String[]> targetsAndReplacements = null;
public ParallelReplacer(String text, List<String[]> targetsAndReplacements) {
this.text = text;
this.targetsAndReplacements = targetsAndReplacements;
run();
}
public void run() {
for(String[] s : this.targetsAndReplacements) {
this.text = performReplace(text, s);
}
}
private String performReplace(String text, String[] targetAndReplacement) {
text = text.replace(targetAndReplacement[0], targetAndReplacement[1]);
return text;
}
}
I execute it like so:
List<String[]> targetsAndReplacements = new ArrayList<String[]>();
targetsAndReplacements.add(new String[] {"a", ""});
targetsAndReplacements.add(new String[] {"e", ""});
targetsAndReplacements.add(new String[] {"i", ""});
targetsAndReplacements.add(new String[] {"o", ""});
targetsAndReplacements.add(new String[] {"u", ""});
String text = "I am trying to perform a replace operation the same string with multiple threads.";
text = new ParallelReplacer(text, targetsAndReplacements.subList(0, targetsAndReplacements.size() / 2)).getResults();
text = new ParallelReplacer(text, targetsAndReplacements.subList(targetsAndReplacements.size() / 2, targetsAndReplacements.size())).getResults();
However, the second thread only executes after the first thread has finished, defeating the purpose of haveing multiple threads. How can I have the two threads executing simultaneously, and then merge the results after they are done?
All your program is in the same thread
A Runnable it's a interface that need to be passed as argument of a thread
You need to execute the ParallelReplacer's instances in new threads
The question that maybe you gonna have, is how get the result, so, you want to use a callback to this, when the execution of the thread is done, the callback is called
public interface IMyCallback {
public void onSucess(String result);
public void onError();
}
Do this in ParallelReplacer
public class ParallelReplacer implements Runnable {
//...
IMyCallback myCallback;
public ParallelReplacer(String text, List<String[]> targetsAndReplacements, IMyCallback myCallback)
{
this.myCallback = myCallback;
this.text = text;
this.targetsAndReplacements = targetsAndReplacements;
run();
}
public void run() {
for(String[] s : this.targetsAndReplacements) {
this.text = performReplace(text, s);
}
myCallback.sucess(text);
}
}
Declare this out of the next method:
int finishedThreads = 0;
ArrayList<String> resultsThreads = new ArrayList<String>();
Do this:
public void callMeWhenAThreadFinished(String result){
finishedThreads++;
resultsThreads.add(result);
if(finishedThreads==2){
//do what you want to do with the results
}
}
and this:
//...
Runnable r1 = new ParallelReplacer(someText, targetsAndReplacements.subList(0, targetsAndReplacements.size() / 2),new IMyCallback() {
#Override
public void onSucess(String result) {
callMeWhenAThreadFinished(result);
}
#Override
public void onError() {
}
});
new Thread(r1).start(); //You forgot this
Runnable r2 = new ParallelReplacer(someText, targetsAndReplacements.subList(targetsAndReplacements.size() / 2, targetsAndReplacements.size()),new IMyCallback() {
#Override
public void onSucess(String result) {
callMeWhenAThreadFinished(result);
}
#Override
public void onError() {
}
});
new Thread(r2).start();
Hugs
While this may be helpful for starting to learn about multithreading, it's not useful for string processing. As stated in the comments, it's not gonna be conducive to merging the string later (at least in its current form).
The answer to your question is that Runnable provides a way to run functionality in a separate thread. But it doesn't provide the background thread itself.
In order to have it work in separate threads, you'd need to do something like this:
Thread first = new Thread(new ParallelReplacer(text, tars.subList(0, tars.size() / 2)));
Thread second = new Thread(new ParallelReplacer(text, tars.subList(tars.size() / 2, tars.size())));
Then you need to use the Thread.join API to wait for completion of the background threads in order to get the results. Or Object.notify in the threaded code, with Object.wait in the code that needs it.
I'm guessing that this is a homework question, so I won't go further here. But please do note that writing multithreaded code is nontrivial, and hard to get right even for very experienced developers. If this isn't just homework, you'll do far better using a proven library to help accomplish your work.
the fundamental problem with your code is that it never uses any threads.
a Runnable in java is just a class that's garunteed to have a void method run that takes no arguments, so you're just calling it as you would any other function
Starting the Threads
to use threading, java has it's own class, Thread,
where thread is expecting a class that implements runnable, so you can do
ParallelReplacer[] replacers=new ParallelReplacer[{number of threads}];
Thread[] threads=new Thread[{number of threads}];
for(int i=0;i<threads.length;i++){
replacers[i]=new ParallelReplacer(...);
threads[i]=new Thread(replacers[i]);
}
this makes an array of Thread objects, ready to go with the replacer they're supposed to run, but it doesn't start them yet. To spawn the thread you call .start() on that thread, beginning it's execution, separately from the main thread, which continues running.
so you would do
for(int i=0;i<threads.length;i++){
thread[i].start();
}
or just start each one after you create it in the previous loop
Output
the main thread of execution runs separately, and will run the next couple of commands before the ones you spawned finish execution, (even if the next command is return!), so you need to at some point tell your main to wait for all the spawned threads to finish
you can do this by calling join() on each spawned thread
for(int i=0;i<threads.length;i++){
threads[i].join();
}
what join does is it tells the currently executing thread (ie main in this case) to wait until the thread it's called on to finish. because of this, it has to be done in a separate loop, other wise you would just have
start thread 1,
stop thread 1
start thread 2
...
and might as well not use threads at all
after all the threads are joined, you can loop through the replacers array, and append all the results.
however
you can do better! all the threads share the same heap, which is where java allocates it's objects. if you change your input string (which is immutable) to a StringBuilder (which can be changed in place), then you could have each thread change it's section, and when they are all joined, the StringBuilder would be all replaced.

Updating JavaFX ProgressIndicator multiple times from a Thread

I am working on the design of a multi-threading app in Javafx and would like to have a TableView with columns for Name and Progress of each Thread. After doing much research I found a similar example of what I am trying to accomplish here:
JavaFX Update progressbar in tableview from Task
(Which points to this: 'https://community.oracle.com/message/10999916')
The problem I am running into, however, is illustrated well in this example; how can you call a 'Task' object multiple times to update a ProgressIndicator?
My understanding from Oracle's documentation is that a Task object "is a one-shot class and cannot be reused". It would seem then that one can only invoke the call() method of a Task object once. I need to update the Task multiple times as it progresses through a Thread class, not call it once and arbitrarily increment through a For loop.
I have read about binding to Listeners and creating Service classes, but I am unsure if those are actual resolutions to this problem. I would therefore like to ask if this is even possible in Javafx, or if perhaps I am overlooking something. In the event someone has accomplished this in the past, it would be tremendously helpful if you might be able to illustrate how through the example provided previously.
Any direction on this would be appreciated, thank you.
-Drew
EDIT 1: I edited my wording as it was inaccurate.
EDIT 2: Here is an example with some pseudo code. Say I had a class with the following code:
public static class TaskEx extends Task<Void>{
#Override
protected Void call(){
updateProgress(.5, 1);
return null
}
public static void callThread() {
TableView<TaskEx> table = new TableView<TaskEx>();
//Some code for data in table.
TableColumn progressColumn = new TableColumn ("Progress");
progressColumn.setCellValueFactory(new PropertyValueFactor("progress");
table.setItems(<data>);
table.getColumns();addAll(progressColumn);
ExecutorService executor = Executors.newFixedThreadPool(<SomeNumber>);
for(TaskEx task : table.getItems(){
Threading.ThreadClass newThread = new Threading.ThreadClass(task);
executor.submit(newThread, <uniqueID>);
}
}
Then say I had a second class for Threading with this logic:
static class ThreadClass extends Thread{
Task progressTask;
public ThreadClass(Task task, Integer id){
progressTask = task;
}
public void run(){
ExecutorService executor = Executors.newFixedThreadPool(<someNumber>);
//This invokes the Task call for the correct progressIndicator in the Tableview.
//It will correctly set the progressIndicator to 50% done.
executor.submit(progressTask);
/* Main logic of the Threading class that involves the 'id' passed in. */
//This will do nothing because you cannot invoke the Task call more than once.
executor.submit(progressTask);
}
}
That is the sort of workflow I need, but I'm unsure how to accomplish this.
It seems like you don't get what we were talking about. You are trying to do your logic in the Thread.run(), and then each thread is creating a Task just to do the update of progress.
What you need is really to shift your logic from Thread.run() to Task.call(). Your thread is really just a thread, and all it does is to run a Runnable object (which is the Task).
public class TaskEx extends Task<Void> {
#Override
protected Void call() {
// Do whatever you need this thread to do
updateProgress(0.5, 1);
// Do the rest
updateProgress(1, 1);
}
}
public static void callThread() {
TableView<TaskEx> table = new TableView<TaskEx>();
ObservableList<TaskEx> data = FXCollections.observableArrayList<>();
data.add(new TaskEx()); // Add the data you need
TableColumn progressColumn = new TableColumn("Progress");
progressColumn.setCellValueFactory(new PropertyValueFactory("progress"));
progressColumn.setCellFactory(column -> {
return new TableCell<TaskEx, Double> {
private final ProgressBar bp = new ProgressBar();
#Override
public void updateItem(Double item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
setText(null);
setGraphic(null);
}
else {
bp.setProgress(item.doubleValue());
setGraphic(bp);
}
}
}
});
table.setItems(data);
table.getColumns().add(progressColumn);
ExecutorService executor = Executors.newFixedThreadPool(data.size());
for (TaskEx task : table.getItems()) {
executor.submit(task);
}
}
This implement removes ThreadClass because there should not be any logic that must be done at a thread sub-class. If you really need to access the thread object as part of your logic, call Thread.getCurrentThread() from your TaskEx.call().
This implement also opens multiple threads doing exactly the same thing (which is quite meaningless). If you need to do a set of different logics, you can either make a set of different Task subclasses, or add a constructor taking in Runnable objects in TaskEx.
E.g.
public class TaskEx extends Task<Void> {
private final Runnable[] logics;
public TaskEx(Runnable[] logics) {
this.logics = logics;
}
#Override
protected Void call() {
for (int i = 0; i < logics.length; i++) {
logics[i].run();
updateProgress(i, logics.length);
}
}
}

How return a result of my method executed in thread?

I've a method who return a result (return an integer), my method is executed in a Thread for load 40 000 objects, i return an integer who count the number objects loaded. My question is, How return the int with the Thread ? Actually, the result is returned directly and is equal to 0.
public int ajouter(params) throws DaoException, ConnectException {
final ProgressDialog dialog = ProgressDialog.show(mActivity, "Title",
"Message", true);
final Handler handler = new Handler() {
public void handleMessage(Message msg) {
dialog.dismiss();
}
};
Thread t = new Thread() {
public void run() {
try {
Str_Requete = "SELECT * FROM Mytable";
ResultSet result = ExecuteQuery(Str_Base, Str_Requete);
Index = addObjects(result);
handler.sendEmptyMessage(0);
} catch (SQLException e) {
e.printStackTrace();
}
}
};
t.start();
return Index;
}
When i call my method in my mainActivity :
int test = myObjs.ajouter(params);
test is equal to 0, the value is returned directly...
My constraint is didnt use AsyncTask.
The whole point of using a Thread is not to block the calling code while performing the task of the thread. Thread.start() returns immediately, but in the meantime a new thread is started in parallel to the current thread which will execute the code in the run() method.
So by definition there is no such thing as returning a value from a thread execution. You have to somehow send a signal back from the thread that performed the task to the thread in which you need the result. There are many ways of doing this, there's the standard Java wait/notify methods, there is the Java concurrency library etc.
Since this is Android, and I assume your calling code is running on the main thread, it's probably wise to use the functionality of Handler. And in fact, you are already doing that - you have a Handler that closes the dialog when the thread is done with its work - but for some reason you seem to expect the result of that work to be ready before it has even started. It would be reasonable to extend your existing Handler with some code that does something with the calculated value and remove the code that returns the value of a variable before or at the same time as it's being calculated by another thread.
I also strongly encourage you to study some concurrency tutorial such as Oracle's concurrency lesson or Android Thread guidelines to really understand what's going on in the background. Writing concurrent code without mastering the concepts is bound to fail sooner or later, because it's in the nature of concurrency that multiple things are happening at the same time, will finish in random order etc. It may not fail often, but you will go crazy wondering why something that works 90% of the time suddenly fails. That's why topics such as atomicity, thread synchronization etc are critical to comprehend.
Edit: Simple Android example of starting a worker thread, performing some work, posting back event to main thread.
public class MyActivity extends Activity {
private Handler mHandler = new Handler();
...
private void doSomeWorkInBackground() {
new Thread() {
public void run() {
// do slow work, this may be blocking
mHandler.post(new Runnable() {
public void run() {
// this code will run on main thread,
// updating your UI or whatever you need.
// Hence, code here must NOT be blocking.
}
});
}
}.start();
// This code will be executed immediately on the main thread, and main thread will not be blocked
}
You could in this example also use Activity.runOnUiThread(Runnable).
Please consider however that AsyncTask basically wraps this kind of functionality in a very convenient way, so if it suits your purposes you should consider using AsyncTask.
If you dont want to use AsyncTask or ForkJoin, then you could implement an Interface e.g. callback in your main class.
In your Example you dont wait until the Thread is done... thread.join
One Solution:
Your Thread is a extra class with an constructor to hold the reference to the calling class.
public Interface callback
{
public int done();
}
public class main implements callback
{
...
CustomThread t = new CustomThread(this)
...
}
public class CustomThread extends Thread
{
private Callback cb;
public CustomThread(Callback cb)
{
this.cb=cb;
}
.
.
.
//when done
cb.done(int)
}

javafx: How to stop an object's background task running when the object itself is deleted from Observable List?

I have a Trade object and whenever it is constructed, it kicks off a task in the background (i.e. say download currentPrice) and start running every 10 seconds.
When the Trade object is created, it is also added to a ObservableList .
Problem: When I delete the object from the ObservableList, I can see that the task (download currentPrice) is still running in the background, although the object is not in the ObservableList anymore.
Is the object actually deleted ?
How can I stop the object's background task from running when the object itself is already removed from the ObservableList?
My goal is to delete the object forever and stop its background task from running as well.
public class Trade{
....
private final ScheduledService<Number> priceService = new ScheduledService<Number>() {
#Override
public Task<Number> createTask(){
return new Task<Number>() {
#Override
public Number call() throws InterruptedException, IOException {
return getCurrentPriceFromGoogleFinance();
}
};
}
};
public Trade(){
priceService.setPeriod(Duration.seconds(10));
priceService.setOnFailed(e -> priceService.getException().printStackTrace());
this.currentPrice = new ReadOnlyDoubleWrapper(0);
this.currentPrice.bind(priceService.lastValueProperty());
startMonitoring();
}
public ReadOnlyDoubleProperty currentPriceProperty(){
return this.currentPrice.getReadOnlyProperty();
}
public final double getCurrentPrice(){
return currentPriceProperty().get();
}
// multi-threading
public final void startMonitoring() {
priceService.restart();
}
public final void stopMonitoring() {
priceService.cancel();
}
....
}
If I understand garbage collector right, your object will live for some time before it gets collected even after you remove it from your list.
To stop the task, add ListChangeListener to your ObservableList. You can get removed Trade and call stopMonitoring() on it. That could hopefuly stop the task.

Running threads in order so that they don't conflict

So, general set up is I have a ListView that gets different values depending on the tab, using fragments.
If I move through the tabs slowely, it works great. But if I quickly flip through the tabs, they "conflict". (Items from one tab will appear on the second).
So, my solution was to make Threads that have the runnable parts, then have a queue and add to the queue, then run them off the queue. I didn't think this would work when I did it, and it didn't.
So, the general code looks like such:
final Thread clearThread = new Thread(new Runnable() {
public void run() {
MyFragment.adapter.clear();
}
});
this.threadQueue.add(clearThread);
if (tab == MenuActivity.TITLES.indexOf("My"))
{
// My Puzzles
final Activity a = this;
final Thread myThread = new Thread(new Runnable() {
public void run() {
MyFragment.getUserPuzzles(a);
}
});
this.threadQueue.add(myThread);
}
else if (tab == MenuActivity.TITLES.indexOf("Top"))
{
// Top Puzzles
final Activity a = this;
final Thread topThread = new Thread(new Runnable() {
public void run() {
MyFragment.getTopPuzzles(a);
}
});
this.threadQueue.add(topThread);
}
//.... More adding the Thread Queue.
while (this.threadQueue.size() != 0)
{
final Thread temp = this.threadQueue.poll();
this.runOnUiThread(temp);
}
This is in my FragmentActivity class, where as the methods, adapters, etc. are all in the fragment class (MyFrag).
So, the general question becomes, how can I alter the ListView in a way that it won't conflict with other values being populated while it's being populated. Some of the threads do get values online, so depending on the connection, they can be fast or slow, but it loads so that it adds while it loads.
Any help would be appreciated.
Thanks!
Put a "current request id" incrementing field in. When you spawn the thread set the request id in the thread. When the thread completes check the field and only update the view if it matches.
i.e.
AtomicInteger currentId = new AtomicInteger(0);
new Processor(currentId.incrementAndGet()).start();
In the processor
if (currentId.get() == ourId) {
// only here do stuff
}
For total safety you could use a synchronized block rather than an AtomicInteger, you probably don't need that in this case but that version would look like:
int currentId = 0;
Object lock = new Object();
synchronized(lock) {
new Processor(++currentId).start(); // Must add then use, not use then add!
}
In the processor
synchronized(lock) {
if (currentId == ourId) {
// only here do stuff
}
}
To sync threads you lock the object, and when two threads must always sync with each other it should probably be just one thread. Why not use separate ListView for each tab.

Categories