Java (Android) multi-threading process

Haris Qureshi :

I am working on application (Matt's traceroute windows version http://winmtr.net/) which creates multi threads each thread has its own process (which execute ping command). ThreadPoolExecutor shutdown all threads after some time( e.g.10 seconds)

ThreadPoolExecutor uses blocking queue(holding tasks before they executed)

int NUMBER_OF_CORES = Runtime.getRuntime().availableProcessors();
ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(
    NUMBER_OF_CORES * 2, NUMBER_OF_CORES * 2 + 2, 10L, TimeUnit.SECONDS, 
    new LinkedBlockingQueue<Runnable>()
);

PingThread.java

private class PingThread extends Thread {

    @Override
    public void run() {
        long pingStartedAt = System.currentTimeMillis();
        // PingRequest is custom object
        PingRequest request = buildPingRequest(params);

        if (!isCancelled() && !Thread.currentThread().isInterrupted()) {

            // PingResponse is custom object

            // Note:
            // executePingRequest uses PingRequest to create a command 
            // which than create a runtime process to execute ping command
            // using string response i am creating PingResponse

            PingResponse pingResponse = PingUtils.executePingRequest(request);

            if (pingResponse != null) {
                pingResponse.setHopLocation(hopLocation);                   
                // publish ping response to main GUI/handler
                publishProgress(pingResponse);
            } else
                Logger.error(
                    "PingThread", "PingResponse isNull for " + request.toString()
                );
        }
    }
}

Now if i create multiple threads say more than 500 in a loop and execute inside pool executor

Executing Threads

PingThread thread = new PingThread(params);
poolExecutor.execute(thread);

I do know that LinkedBlockingQueue holds tasks before they executed. Each thread's process takes maximum 200 to 400ms but generally it is less than 10ms

What i am doing

for (int iteration = 1; iteration <= 50/*configurable*/; iteration++) {

    for (int index = 0; index < 10/*configurable*/; index++) {
        PingThread thread = new PingThread(someParams);
        poolExecutor.execute(thread);
    }

    try {
        Thread.sleep(500);
    } catch (InterruptedException e) {
        Logger.error(false, e);
    }   
}

50 iterations will take about 25 seconds, here i only have up-to 40 ping responses rest consider as loss due to time out. If i increase iterations loss increases too (exponentially due to increase in no of threads)

Observation:

I am running this application on Galaxy S6 which has 8 cores, application pool size is 16 and maximum pool size is 16 + 2, i do know that processor runs only one thread at a time, it shares a quantum time for parallel processing.

By observing ThreadPoolExecutor on timely basis, i see many tasks in queue, after timeout there are still many threads present in queue due to LinkedBlockingQueue

If i decrease no of threads it works fine but if increase it creates problem

Problem:

  • Ping responses decreases when i use devices with dual core processor.
  • Why there are many threads present in queue, where each thread takes about 10 to 50ms (increase threads time will increase uptp 300ms or more)?
  • It should complete with in given time, why its not?
  • How to overcome this problem?
  • Should i use ConcurrentLinkedQueue but it uses Producer/consumer model, somehow ThreadPoolExecutor (i think it is) uses this model too.
  • LinkedBlockingQueue holds tasks before they executed (threads are idle or in queue), how to overcome this?
  • By setting Thread.MAX_PRIORITY for latter iterations does't solve the problem (later iteration's thread are in queue)
  • Decreasing no of threads solves the problem why? because there are less no threads present in queue?
  • Is there any way to check, if threads present in queue entertain them then execute other, without blocking other threads but within given time.
  • Adding extra time like 5 seconds is not a solution
  • Changing corePoolSize like in How to get the ThreadPoolExecutor to increase threads to max before queueing? is not working in my case.

During testing Memory and Processor usage are with in a limit.

Detail answer/help is required.

Edit

When application goes into background there is no loss and user CPU usage drops to 0-2% while on focus app took 4-6% of cpu usage. Is it due to UI and other ralted stuff, i tried to remove all unnecessary code also i did change PingThread to PingTask

PingTask implements Runnable {/*....*/}

Note: I created separate java based application using same code and it works fine on desktop, so can we say it's android OS specific issue?

Haris Qureshi :

Observation:

After creating and observing a independent java application (logs) using same code, I came to know the followings:

  • Somehow android OS architecture and/or processor is limiting the number of threads.
  • LinkedBlockingQueue holds tasks before they executed, so if we have a long queue later threads in queue will have to wait more.
  • Increase/Dynamic corePoolSize and maxPoolSize is doing the same, they added threads in queue
  • Application uses 4-6% of CPU so we can't say CPU is overloading or utilizing full application resources but when application goes into background (GUI or other related OS and/or application based threads may stop or interrupted) CPU uses drops to 0-3%.

Solution:

For 50 iterations and 10 inner creates 500 threads now i did two things:

  • Increase Thread.sleep(millis) time with some calculation involves.
  • Decrease number of threads for each iteration. I was creating 10 threads now Math.ceil((double) 10 / 3) = 3 so we have 3 sequential PingUtils.executePingRequest(pingRequest) for each thread i.e. 3 * 3 = 9 remains 1 so we will create a separate thread for last request. For each iteration instead of creating 10 threads now i am creating 4 threads.
  • Using this approach now i have 200 threads instead of 500 which solves the issue.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=451886&siteId=1