I have a set of HTTP reqeuests that each response adds an entry to ArrayList. Later I use that list to make some checks.
How can I make the program wait until all the requests are done and the list is filled before continuing to checks?
EDIT
code sample:
class BackgroundTask extends AsyncTask<Void,String,Void>{
List<Integer> responses;
#Override
protected synchronized Void doInBackground(Void... params) {
responses= new ArrayList<Integer>();
for( int i=0; i<10; i++ ){
restAPI.getNextInt( // SEND HTTP REQUEST
new Response.OnSuccess() { // ON SUCCESS CALLBACK
#Override
public void onResponse(Integer i) {
responses.add(i);
}},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}});
}
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
}
}
And in my main thread:
BackgroundTask bt = new BackGroundTask();
bt.execute();
bt.get(10000, TimeUnit.MILLISECONDS); // THIS DOESN'T WAIT
if( bt.responses.contains(10) ){
...
}
I didn't provided code before because I'm looking for the general solution not a specific for me
EDIT 2
Here is my second try that it didn't work. I put everything in the main thread.
final Semaphore sema = new Semaphore(-params.size()+1);
final List<Integer> responses = Collections.synchronizedList(new ArrayList<Integer>());
for( final Param p : params ){
new Thread(){
#Override
public void start(){
restAPI.nextInt(p, // SEND HTTP REQUEST
new Response.OnSuccess() { // ON SUCCESS CALLBACK
#Override
public void onResponse(Integer i) {
System.out.print("aaaaa");
sema.release();
responses.add(i);
}},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
sema.release();
}});
}
}.start();
}
try {
sema.acquire();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
if( responses.contains(10) )
...
Now what happens is that everything blocks/stops in sema.acquire() and aaaaa never prints. If I remove sema.acquire() then aaaaa prints.
The whole code is in a protected void onPostExecute(Void result) of an AsyncTask if this matters ...
Are you familiar with semaphores? Basically a semaphore has a number associated with it. Lets say you have five http requests to make. You will initialize the semaphore's number to -4. From your main thread that needs to wait for the list to be filled, call the acquire method on the semaphore. This will cause the thread to block (wait) until the semaphore's number has a value of 1. In each of your async threads, call "release" on the semaphore after the async thread is done adding its entry to the list. Each time you call release on the semaphore, the semaphore's number is incremented by 1. Thus when all of the async threads are finished, the semaphore will have a value of 1, allowing the main thread to continue executing. For future reference, calling acquire on the semaphore will decrement the value back to zero.
import java.util.concurrent.Semaphore;
Semaphore sema = new Semaphore(-4);
for each http request that needs to be made:
spawn a separate thread to execute this function {
do http request and insert entry into list
sema.release();
}
sema.acquire(); // block main thread until http requests are done
doStuff(); //The list is already filled, do whatever you need to do.
Related
I have the following method, that called every time I click over a button, this results to start a new thread again and again when the button is pressed, that results to multiple initialisation of thread, however I want only one thread should get executed, how can I achieve this.
private void scheduleMessages() {
new Thread(new Runnable() {
#Override
public void run() {
//Some operations
}
}).start();
}
Note: this is a small method and I don't want to create a separate class, just to make it singleton, so a solution without singleton pattern will be appreciated.
if you cannot make instance of this to check isActive() you should make a semaphore variable - a boolean, that you set to true when you start thread and set to false when you are done.
private void scheduleMessages() {
if (!taskRunning){
new Thread(new Runnable() {
#Override
public void run() {
taskRunning = true;
//Some operations
taskRunning = false;
}
}).start();
}
}
Have that thread be a background thread - maybe initialize it when the button is pressed the first time.
Have that thread listen to a queue - and act upon messages in that queue.
Whenever the button is pressed again, put a new message into the queue.
If your need to execute every requests but on a specific number of threads, you can use a thread pool and let the executor manage the queue .
private ExecutorService services;
private final static int POOL_SIZE = 1;
public MessagesService(){
services = Executors.newFixedThreadPool(POOL_SIZE);
}
public void scheduleMessages(Runnable r){
services.submit(r);
}
If you call addCall x times, x thread will be executed at the end but will never use more than the number of thread available in the pool. Here, 1 thread.
For a system that only accept one request, you can use the same approch but check the Future returned by a single thread executor. That way, you can check the status of the service.
private ExecutorService services;
private Future<?> lastCall;
public MessagesService() {
services = Executors.newSingleThreadExecutor();
lastCall = null;
}
public synchronized void scheduleMessages(Runnable r) {
if(!isScheduled()){
lastCall = services.submit(r);
}
}
public boolean isScheduled(){
return lastCall != null && !lastCall.isDone();
}
That way, the Runnable doesn't need to update a flag, which give a reusable solution.
Here is a sample of the Runnable to test these codes :
new Runnable() {
System.out.println("Running");
try {
Thread.sleep(500);
} catch (Exception e) {
e.printStackTrace();
}
}
I've MyDataService which collects data by multiple GetSomeDataThread in parallel. Each GetSomeDataThread requests data synchronously via RequestFuture and StringRequest.
I got a timeout. I solved it by wrapping the request with another Thread and Runnable.
The timeout is gone, but I'm now getting the data asynchronously (see the comments in call()).
I found a lot of good answers on SO, but no duplicate.
Any ideas? Thanks in advance!
EDIT: To clarify the goal: result[0] should contain the content of future.get(), but it contains the default value "nothing". I probably need to wait for run() to finish, but don't know how.
EDIT 2: I can use a StringRequest (asynchronous) in call(), but not with future (synchronous). If I use StringRequest without wrapping it with another Thread, the app freezes and I'll get a timeout exception after a while (the URLs are fine).
public class MyDataService extends Service {
// ...
protected Summary summary;
protected void loadSummary() throws Exception {
Collection<GetSomeDataThread> threads = new ArrayList<>();
// loop
threads.add(new GetSomeDataThread("a"));
threads.add(new GetSomeDataThread("b"));
threads.add(new GetSomeDataThread("c"));
ExecutorService executorService = Executors.newFixedThreadPool(threads.size());
List<Future<JSONObject>> results = executorService.invokeAll(threads);
for (Future<JSONObject> result : results) {
// do something with the result:
// result.get()
}
executorService.shutdown();
}
}
-
public class GetSomeDataThread implements Callable<JSONObject> {
// ...
public GetSomeDataThread(String actionId) {
// ...
url += "&actionId=" + actionId;
}
#Override
public JSONObject call() throws Exception {
final String[] result = {"nothing"};
Thread t = new Thread(new Runnable() {
#Override
public void run() {
RequestFuture<String> future = RequestFuture.newFuture();
StringRequest request = new StringRequest(Request.Method.GET, url, future, future);
requestQueue.add(request);
result[0] = future.get();
Log.d(LOG_TAG, result[0]); // outputs the correct value, but delayed
Thread.currentThread().interrupt();
}
});
t.start();
// TODO: wait for thread + runnable to finish
// t.join(); just blocks
// result[0] equals "nothing"
return new JSONObject().put("result", result[0]);
}
}
I'm struggling with a network connection class I've created. The result of the Runnable I create returns a JSON object that contains all the information needed from the server. The thread runs, and receives the data perfectly, but of course, the program keeps running in the meantime, which results in a JSONException as being NULL.
I created a class called NetworkManager, which has the following method (jsonResponse is initialized at the beginning of the class)
JSONObject jsonResponse;
public void createNetworkThread(Context context, final String requestURI, final RequestBody formParameters) {
Runnable runnable = new Runnable() {
#Override
public void run() {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url(requestURI).post(formParameters).build();
Response response = null;
try {
response = client.newCall(request).execute();
String stringResponse = response.body().string();
NetworkManager.this.jsonResponse = new JSONObject(stringResponse);
// This works perfectly, "message" is received and printed to the log //
Log.d("Net", NetworkManager.this.jsonResponse.getString("message"));
} catch (IOException e) {
Log.d("Net", "Failed");
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
}
};
Thread thread = new Thread(runnable);
thread.start();
}
The above is called from the Activity, as:
Net.createNetworkThread(SignupActivity.this, requestURI, formVars);
JSONObject jsonResponse = Net.jsonResponse;
The JSON object jsonResponse is returning as NULL because the Thread is still accessing the server for the response.
I need to figure out how to stop the jsonResponse Object from being populated by Net.jsonResponse until the thread completes in order to stop it from returning NULL.
Any help?
I would only agree to the comments on your question and let you know, what you can do here.
If you are creating a thread just to get of the main UI thread to do the Network call you probably want to use OkHttp feature which allows you to get the Network call off the thread and provides you with callbacks to get the result something like this. you can check some example here
Request request = new Request.Builder()
.url(url)
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Request request, IOException e) {
}
#Override
public void onResponse(Response response) throws IOException {
// this is the callback which tells you the network call was successful, If like to make some changes to UI, you should call `runOnUiThread`.
"YourClassName".this.runOnUiThread(new Runnable() {
#Override
public void run() {
}
});
}
});
or you can use AsyncTask which also gets your job done off the main UI thread and gives you the result in the callbacks.
private class MyTask extends AsyncTask<Void, Void, Void> {
//you can change the Type Void, Void, Void here to something which you want
//First Void belongs to doInBackground(Void... avoid)
//Second Void belongs to onProgressUpdate(Void... progress)
//Third Void belongs to onPostExecute(Void result)
// you may change these as you fit,
//when you want to start this class with your argument you can do something like this.
//new MyTask().execute("your argument to doInBackground");
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Void doInBackground(Void... params) {
// this is the method where you provide your implementation for doing a task off the main UI thread.
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
// in this callback you are back in the main UI thread to make changes to UI depending on your response
}
}
here is an example of AsyncTask
If you want to offload the main thread, you should consider that the parallel task could finish it's execution after, generally speaking, any amount of time. Sure, you can wait in the main thread for the child thread to finish (using 'join()'), though this is kind of questionable in terms of speed gain.
Anyway, answering your question:
I need to figure out how to stop the jsonResponse Object from being
populated by Net.jsonResponse until the thread completes in order to
stop it from returning NULL.
I suggest you change
public void createNetworkThread(...
to
public Thread createNetworkThread(...
{
...
Thread thread = new Thread(runnable);
thread.start();
return thread;
}
And consequently
Thread t = Net.createNetworkThread(SignupActivity.this, requestURI, formVars);
t.join(); // Wait until 't' finishes -- try-catch is omitted for the sake of demo.
JSONObject jsonResponse = Net.jsonResponse;
This, apparently, opens question of performance, since main thread will be effectively completely blocked by 't.join()' until the child thread will finish.
Answering the question in the topic: in Java 8 you can use lambda functional interface like this:
package multithreaded;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Multithreaded {
public static void main(String[] args) throws Exception {
Logger logger = LoggerFactory.getLogger("Main");
Worker<String, String> worker = new Worker<String, String>(
(String s) ->
{ // This is actual call-back code.
// It will be called by method 'apply' of interface 'Function' in the 'Worker'.
// It will accept String parameter and pass it in this block as variable 's'
logger.info("Embrace the beauty and power of Java 8! "+s); // yes, we can use local variables of the parent thread.
return "Call-Back "+s;
}
);
logger.info("Application starts new Worker.");
worker.start();
logger.info("Worker is running in background.");
Thread.currentThread().sleep(500); // Simulate some activity here...
logger.info("Result is unpredictable (could be null): "+worker.getResult());
// Wait here until worker is fully finished
worker.join();
logger.info("Result is predictable: "+worker.getResult());
}
}
Worker.java:
package multithreaded;
import java.util.function.Function;
public class Worker<T extends String, R extends String> extends Thread {
private final Function<T, R> callBack;
private volatile R result;
public Worker(Function<T, R> callBack)
{ this.callBack = callBack; }
#Override
public void run()
{
try{
int i = (int)(Math.random()*1000);
// simulate some activity unpredictable in terms of duration
Thread.currentThread().sleep(i);
// After "activity" is finished -- call the call-back function and get result in local variable.
// (Synchronization ommited for the sake of simplicity)
result = this.callBack.apply((T)("Result "+i)); // now let's call the call-back function and save the result in local variable.
}
catch(InterruptedException e)
{e.printStackTrace();}
}
// Getter for the local variable, populated by call-back function.
// (Synchronization ommited for the sake of simplicity)
public R getResult()
{ return this.result; }
}
Running above code multiple times, you will notice that from the parent thread's perspective the result is still unpredictable until the child thread is completely finished.
P.s. I suggest you re-think entire logic of data processing in your app and consider re-factoring towards entirely independent multi-threaded processing (perhaps using producer-consumer logic).
My app uses a lot of AsyncTasks. It is a web app after all. And when I keep track of the Debug tab, I notice every AsyncTask says running behind it and after 5 AsyncTasks, I can't start any AsyncTasks. I fixed it by changing the executor to THREAD_POOL_EXECUTOR which allows 15 threads to be pooled. But the AsyncTasks still show as running.
The AsyncTasks all have InputStreams in them and BufferedReaders in them to read the JSON, but I never call the close() method on the Streamers and Readers. Could this be it, or will the AsyncTask be collected after it's finished no matter what?
If that's the deal, then why can't I run more than 5 AsyncTasks in my app?
Seeing as I put a bounty on it, I will explain this more explicitly
The AsyncTasks all go through their methods. All of them are built the same exact way, except with different BasicNameValuePairs. I am 100% sure there is no easy mistake made in the code.
Here is an example of one of the AsyncTasks:
private class RunningEvent extends AsyncTask<Void, Void, Response> {
#Override
protected void onPreExecute() {
if (Constants.isOnline(getApplicationContext())) {
super.onPreExecute();
} else {
Toast.makeText(getApplicationContext(),
"No internet connection", Toast.LENGTH_LONG).show();
return;
}
}
#Override
protected Response doInBackground(Void... empty) {
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(URL);
try {
List<NameValuePair> values = new ArrayList<NameValuePair>(5);
values.add(new BasicNameValuePair("tag", "eventRunning"));
values.add(new BasicNameValuePair("userid", String
.valueOf(response.user.userid)));
post.setEntity(new UrlEncodedFormEntity(values));
HttpResponse httpresponse = client.execute(post);
HttpEntity entity = httpresponse.getEntity();
InputStream stream = entity.getContent();
Log.i("MenuActivity",
"Input streamed, parsing Gson for existing events");
Gson gson = new Gson();
Reader reader = new InputStreamReader(stream);
eventresponse = gson.fromJson(reader, Response.class);
return eventresponse;
} catch (Exception e) {
e.printStackTrace();
Log.e("RunningEvent", "Error sending data to Server");
}
return null;
}
#Override
protected void onPostExecute(Response result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
Log.i("MenuActivity", "Binding button");
if (eventresponse != null) {
if (eventresponse.success == 1) {
eventresponse.user = response.user;
bActivity.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
Intent i = new Intent("com.xxx.xxx.EVENT");
i.putExtra("response", eventresponse);
running = false;
switcher.cancel(true);
MenuActivity.this.finish();
startActivity(i);
}
});
} else {
bActivity.setText("Nieuw activity");
bActivity.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
Intent i = new Intent("com.xxx.xxx.NEWEVENT");
i.putExtra("response", response);
running = false;
switcher.cancel(true);
MenuActivity.this.finish();
startActivity(i);
}
});
}
} else {
Log.i("RunningEvent", "Response is null");
}
}
}
The example above is the sometimes gets runned as the 6th AsyncTask and it will never enter the doInBackground() method. I believe this is the 5 Thread limit of the SERIAL_EXECUTOR. I "fixed" the problem by putting most AsyncTasks in THREAD_POOL_EXECUTOR, but this is just avoiding it.
What could be the reason that these AsyncTasks never stop running and clogging up the Executor?
android.os.AsyncTask come with two built-in executor. if using SERIAL_EXECUTOR, there is no threadpool and all AsyncTask get execute one at a time in serial order. if using THREAD_POOL_EXECUTOR (I suppose this is what you refer in the question), this allows up to maximum 128 AsyncTask get execute in parallel.
The number 5 you refer and see from debugging is the corePoolSize of underlying threadpool (AKA. THREAD_POOL_EXECUTOR), which is different from maximumPoolSize. check out AsyncTask source code and see how threadpool is implemented:
private static final int CORE_POOL_SIZE = 5;
private static final int MAXIMUM_POOL_SIZE = 128;
private static final int KEEP_ALIVE = 1;
... ...
/**
* An {#link Executor} that can be used to execute tasks in parallel.
*/
public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
Check out ThreadPoolExecutor API to see what is the default threadpool behavior created by calling this constructor. Generally speaking, corePoolSize is the number of threads to keep in the pool, even if they are idle, unless allowCoreThreadTimeOut is set.
Those 5 AsyncTask you see in debug are actually on core threads which are finished and become idle but never terminated, you can alter this behavior by calling ThreadPoolExecutor.allowCoreThreadTimeOut(boolean).
More story on SERIAL_EXECUTOR
I said SERIAL_EXECUTOR does not use threadpool, this is not true. SERIAL_EXECUTOR is indeed delegate the real work to THREAD_POOL_EXECUTOR, but using ArrayDeque to control the submission of next tasks (next task is submitted iff the previous task is finished), check out the source:
private static class SerialExecutor implements Executor {
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
Runnable mActive;
public synchronized void execute(final Runnable r) {
mTasks.offer(new Runnable() {
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
});
if (mActive == null) {
scheduleNext();
}
}
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
So whatever you use SERIAL_EXECUTOR or THREAD_POOL_EXECUTOR, there are always 5 core threads shown in threadpool even they are finished and become idle. However, number of core thread (configured by corePoolSize) is not the number of threads (configured by maximumPoolSize) currently running in threadpool.
I have a simple Question:
I have a Thread named rlMF. I created it this way:
public Thread rlMF = new Thread(new Runnable() {
public void run() {
reloadMissingFiles();
stopTh();
}
public void stopTh() {
activityStopped = true;
}
});
Now i want to call the stopTh Function from outer Thread. Why can't i simply call rlMF.stopTh(); and what can i do else?
Example:
protected void onPause() {
Log.d("Info", "destroying...");
activityStopped = true;
rlMF.stopTh();
super.onPause();
}
Is not working...
Because the interface accessible is from Thread. In order to have you method accessible from out, you need to specify a type that exposes this method.
And if you take a look carefully the method is implemented in the instance of Runnable. Not even in Thread.
You could have something like this if you really need to access the Runnable object:
class MyRunnable implements Runnable {
public void run() {
...
}
public void fooBar() {
...
}
}
public void someMethod() {
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
...
myRunnable.fooBar();
...
}
An example for Francisco approach, besides what you are trying to achieve. Maybe this can point you in the right direction
public class CustomRun implements Runnable {
public void run() {
reloadMissingFiles();
stopTh();
}
public void stopTh() {
activityStopped = true;
}
}
In your Code
// start thread with custom runner
CustomRun runner = new CustomRun();
new Thread(runner).start();
// call your stopTh method on CustomRun class
protected void onPause() {
Log.d("Info", "destroying...");
activityStopped = true;
runner.stopTh();
super.onPause();
}
Your goal is to interrupt the thread from onPause. There are several ways to do it, but essentially, you will need to include some interruptibility in reloadMissingFiles.
Option 1
You can use a boolean flag like you did - you need to declare it as volatile to make sure the changes are visible across threads:
private volatile boolean activityStopped = false;
public void reloadMissingFiles() {
while (!activityStopped) {
//load small chunks so that the activityStopped flag is checked regularly
}
}
public Thread rlMF = new Thread(new Runnable() {
public void run() {
reloadMissingFiles(); //will exit soon after activityStopped has been set to false
}
});
protected void onPause() {
//This will stop the thread fairly soon if the while loop in
//reloadMissingFiles is fast enough
activityStopped = true;
super.onPause();
}
Option 2 (better approach)
I don't know what you do in reloadMissingFiles, but I suppose it is some sort of I/O operations, which are generally interruptible. You can then have an interruption policy where you stop as soon as an InterruptedException is caught:
public void reloadMissingFiles() {
try {
//use I/O methods that can be interrupted
} catch (InterruptedException e) {
//cleanup specific stuff (for example undo the operation you started
//if you don't have time to complete it
//then let the finally block clean the mess
} finally {
//cleanup (close the files, database connection or whatever needs to be cleaned
}
}
public Thread rlMF = new Thread(new Runnable() {
public void run() {
reloadMissingFiles(); //will exit when interrupted
}
});
protected void onPause() {
runner.interrupt(); //sends an interruption signal to the I/O operations
super.onPause();
}
Note: you can also read this article for a more in depth version of it.