Dima
Dima

Reputation: 443

Running long jobs in parallel and only after all jobs finishes to update the UI

I'm building an Android app and I have some issues with the architecture - how to implement many calls on different threads.

I have 2 methods:

ConnectAndGetId() //takes 2-3 seconds
GetTokenID(ID)    //takes 2-3 seconds

First I need to call ConnectAndGetId() and then after getting a result ID to call GetTokenID(ID). After I get a tokenID I need to call 4 methods and pass them tokenID:

getNames (tokenID) //takes 4 second
getPhones (tokenID) //takes 7 seconds
getIds(tokenID) //takes 2 seconds
getDetailObject(tokenID) //takes 5 seconds

The idea is to show the data ONLY after I have the result from the ALL 4 methods. There is no need to execute them one by one because It will take a lot of time (18 sec), I want to run them in parallel and in the end with all the data to update the UI.

I thought to do the next thing:
Start AsyncTask and call to ConnectAndGetId,in onPostExecute() start another AsyncTask and run there GetTokenID(ID). after I run GetTokenID(ID) I'll return the result to UI thread and with the returned data I'll start 4 new threads, that each thread will call one of the 4 methods. I can count the finished threads,and when I got all the 4 result I can update the UI with handler.

Is it the right approach ? maybe I should not create 4 threads for 4 methods? else to create one handlerThread and pass the 4 methods to his handler so the Thread will pool them - but it will be one by one.

Is that the correct idea or It can be done better?

Upvotes: 0

Views: 358

Answers (3)

initramfs
initramfs

Reputation: 8415

Regarding if running four threads is appropriate for your situation only you can judge. It increases the complexity of the program and requires multithread access protection and synchronization on relevant data. Also consider if parallel access can actually speed up your computation. Parallel access only speeds up if the limiting factor is single-thread computational speed, if the limit lies with data bandwidth you won't see any significant gain in speed.

To your problem of four threads complete to one UI update you can try using a CyclicBarrier to lock all threads until the last one finishes execution.

The following shows an example:

// Create a CyclicBarrier with 4 parties and a target action to update UI

CyclicBarrier barrier = new CyclicBarrier(4, new Runnable(){
    public void run(){
        //Do your UI updates here (remember any direct UI must be on UI thread)
    } 
});

// Pass above CyclicBarrier to your four threads


// Skeleton of Runnable instance for each of the four threads.

Runnable r = new Runnable(){
    public void run(){
        // Run desired long-running method

        // getNames, getPhones, etc

        // Call await() from CyclicBarrier instance (exception handling not shown)

        barrier.await();
    }
};

With the above code each thread that finishes will block on the await method until the fourth thread calls await() in which all threads unblock and the last thread runs the runnable passed to the CyclicBarrier at the start.

Upvotes: 0

eleven
eleven

Reputation: 6855

It's normal approach. But I would recommend you to use Executor but not create Threads. Sample:

public class TasksSample {
    public static void execute(){
        ExecutorService executorService = Executors.newFixedThreadPool(4);
        executorService.submit(new Task("A"));
        executorService.submit(new Task("B"));
        executorService.submit(new Task("C"));
        executorService.submit(new Task("D"));
        executorService.shutdown();
        try {
            executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("all tasks finished");
    }

    private static class Task implements Runnable{

        private String taskId;

        public Task(String taskId) {
            this.taskId = taskId;
        }

        @Override
        public void run() {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("finished task: " + taskId);
        }
    }
}

Upvotes: 1

Angmar
Angmar

Reputation: 599

Very good question indeed. I think your aproach is correct, but I wouldn't create the GetTokenID thread on the onPostExecute(). I think it's better to use a Listener to ensure that you got the result you need. On the next step I would also use a Listener that would call your 4 methods.

The question is: do you need the 4 methods to finish to update your UI? then you should use a Listener with a synchronized block that would only enter when your 4 methods have finished. You can use a method that checks that these methods have got their results and when the 4 have completed, update the UI.

In case you don't need the 4 methods to finish to update the UI I would just put a ProgressDialog in the UI and update it method-by-method. In the last one dismiss the ProgressDialog and unblock the UI.

I hope it helps you out bro, good luck with coding!

Upvotes: 0

Related Questions