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.
Related
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)
}
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.
I have a callback function in which i receive a string.
This string is to be passed to a separate thread for processing since the processing takes time.
Also, since multiple callbacks can come simultaneously, I would like to have a synchronized lock till i pass the string into the new thread. But I do not wish to have the new thread (where processing is going on) to be locked also.
Could someone please help me figure out the design for this?
I have written the following code but in this I think in this no callbacks can be received till the whole processing of the separate thread is also done, thereby defeating the whole purpose of this new thread.
String sLine;
onClick(String line){
synchronized (lock) {
sLine = line;
new Thread(new Runnable() {
#Override
public void run() {
doProcessing(Sline);
}).start();
}
}
Also, since multiple callbacks can come simultaneously, I would like to have a synchronized lock till i pass the string into the new thread.
A: I don't think you need to put a lock here. This string is not accessed by multi-thread.
But I do not wish to have the new thread (where processing is going on) to be locked also.
A: As I see nothing was locked here :) I think it could be better if you do something like that:
Create an class Runner implement Runnable, this class will do processing
Everytime you got callback, use ThreadPoolExecutor to execute this Runner. This help you reuse Thread instance.
Note that: These line code doesn't need to synchronized, put synchronized inside processing method if you need.
// Implement class Runner
public class Runner implements Runnable {
private String mLine;
public Runner(String line) {
mLine = line;
}
#Override
public void run() {
process();
}
public void process() {
// Do processing with mLine
// Put synchronized if you need, it bases on your context
}
}
// Initialize thread pool
private ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 100, 1000, TimeUnit.SECONDS, new LinkedBlockingDeque<Runnable>());
// Execute runner when receiving callback
onClick(String s) {
Runner runner = new Runner(s);
executor.execute(runner);
}
Try changing like below
String sLine;
onClick(final String line){
sLine = line;
new Thread(new Runnable() {
#Override
public void run() {
doProcessing(line);
}).start();
}
While coding a computation-heavy application, I tried to make use of the SwingWorker class to spread the load to multiple CPU cores. However, behaviour of this class proved to be somewhat strange: only one core seemed to be utilized.
When searching the internet, I found an excellent answer on this web (see Swingworker instances not running concurrently, answer by user268396) which -- in addition to the cause of the problem -- also mentions a possible solution:
What you can do to get around this is use an ExecutorService and post
FutureTasks on it. These will provide 99% of the SwingWorker API
(SwingWorker is a FutureTask derivative), all you have to do is set up
your Executor properly.
Being a Java beginner, I am not entirely sure how to do this properly. Not only that I need to pass some initial data to the FutureTask objects, I also need to get the results back similarly as with SwingWorker. Any example code would therefore be much appreciated.
nvx
==================== EDIT ====================
After implementing the simple yet elegant solution mentioned in FutureTask that implements Callable, another issue has come up. If I use an ExecutorService to create individual threads, how do I execute specific code after a thread finished running?
I tried to override done() of the FutureTask object (see the code below) but I guess that the "show results" bit (or any GUI related stuff for that matter) should be done in the application's event dispatch thread (EDT). Therefore: how do I submit the runnable to the EDT?
package multicoretest;
import java.util.concurrent.*;
public class MultiCoreTest {
static int coresToBeUsed = 4;
static Future[] futures = new Future[coresToBeUsed];
public static void main(String[] args) {
ExecutorService execSvc = Executors.newFixedThreadPool(coresToBeUsed);
for (int i = 0; i < coresToBeUsed; i++) {
futures[i] = execSvc.submit(new Worker(i));
}
execSvc.shutdown();
// I do not want to block the thread (so that users can
// e.g. terminate the computation via GUI)
//execSvc.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
}
static class Worker implements Callable<String> {
private final FutureTask<String> futureTask;
private final int workerIdx;
public Worker(int idx) {
workerIdx = idx;
futureTask = new FutureTask<String>(this) {
#Override
protected void done() {
Runnable r = new Runnable() {
#Override
public void run() {
showResults(workerIdx);
}
};
r.run(); // Does not work => how do I submit the runnable
// to the application's event dispatch thread?
}
};
}
#Override
public String call() throws Exception {
String s = "";
for (int i = 0; i < 2e4; i++) {
s += String.valueOf(i) + " ";
}
return s;
}
final String get() throws InterruptedException, ExecutionException {
return futureTask.get();
}
void showResults(int idx) {
try {
System.out.println("Worker " + idx + ":" +
(String)futures[idx].get());
} catch (Exception e) {
System.err.println(e.getMessage());
}
}
}
}
A couple of points:
you rarely need to use FutureTask directly, just implement Callable or Runnable and submit the instance to an Executor
in order to update the gui when you are done, as the last step of your run()/call() method, use SwingUtilities.invokeLater() with the code to update the ui.
Note, you can still use SwingWorker, just, instead of calling execute(), submit the SwingWorker to your Executor instead.
if you need to process all results together when all threads are done before updating the gui, then i would suggest:
have each worker stash it's results into a thread-safe, shared list
the last worker to add results to the list should then do the post-processing work
the worker which did the post-processing work should then invoke SwingUtilities.invokeLater() with the final results
I tried to make use of the SwingWorker class to spread the load to
multiple CPU cores. However, behaviour of this class proved to be
somewhat strange: only one core seemed to be utilized.
no idea without posting an SSCCE, short, runnable, compilable,
SSCCE could be based on
SwingWorker is designated creating Workers Thread for Swing GUI, more in this thread
I have this code:
public class JsoupParser {
ArrayList<CompanyInfo> arr = new ArrayList<CompanyInfo>();
public JsoupParser() {}
public ArrayList<CompanyInfo> parse(final String link) throws IOException {
Runnable runnable = new Runnable() {
public void run() {
// Here I do some operations and then assign some value
// to my `arr` ArrayList
}
};
new Thread(runnable).start();
return arr; // error here, as expected
}
}
System immediately returns arr, which at that point is null.
How can I return arr only after Thread finishes? How can I be informed, that Thread has finished?
How can I return arr only after Thread finishes? How can I be
informed, that Thread has finished?
Thread parseThread = new Thread(runnable).start();
parseThread.join();
return arr;
There's the literal answer to your question but zmbq's answer is more fitting for what you're after.
The whole point of using another thread, is to have it run while your main thread does something else. If you want your parse method to return the array when it's done, it shouldn't start another thread.
However, since I suppose you do want the calculation to take place in the background, you need to do something else. Why don't you take a look at AsyncTask? It is probably what you need.