0

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 ...

ApollonDigital
  • 913
  • 3
  • 15
  • 24

1 Answers1

1

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.
Kevin Wheeler
  • 1,331
  • 2
  • 15
  • 24
  • When I put a Semaphore(0) or below, everything stop/block. I don't not what might be at fault. I have a thread for every HTTP request ... – ApollonDigital Aug 12 '15 at 22:37
  • Can you place a print statement before you call sema.release(); and make sure that the release is being executed at all? You should also put one before sema.acquire() to ensure that is where it is blocked. – Kevin Wheeler Aug 12 '15 at 22:40
  • Based on the fact that it happens when only when you use 0 or below, it seems that release isn't being called. – Kevin Wheeler Aug 12 '15 at 22:45
  • I added a print inside the response callback. It didn't print. I removed sema.acquire from my main thread and it prints ... I don't know why. I use seperate threads to send requests. I also want to mention that the whole code is inside `onPostExecute()` of an AsyncTask. If this matters – ApollonDigital Aug 12 '15 at 22:50