简体   繁体   English

Java(Android)多线程进程

[英]Java (Android) multi-threading process

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). 我正在开发应用程序( Matt的traceroute windows版本http://winmtr.net/ ),它创建多个线程,每个线程都有自己的进程(执行ping命令)。 ThreadPoolExecutor shutdown all threads after some time( eg10 seconds) ThreadPoolExecutor在一段时间后关闭所有线程(例如10秒)

ThreadPoolExecutor uses blocking queue(holding tasks before they executed) ThreadPoolExecutor使用阻塞队列(在执行之前保存任务)

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 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 现在,如果我创建多个线程在循环中说超过500并在池执行器内执行

Executing Threads 执行线程

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

I do know that LinkedBlockingQueue holds tasks before they executed. 我知道LinkedBlockingQueue在执行之前保存任务。 Each thread's process takes maximum 200 to 400ms but generally it is less than 10ms 每个线程的进程最多需要200到400毫秒,但通常小于10毫秒

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. 50次迭代将需要大约25秒,在这里我只有最多40个ping响应,其余被视为因超时而丢失。 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. 我在Galaxy S6上运行这个应用程序,它有8个内核,应用程序池大小为16,最大池大小为16 + 2,我知道处理器一次只运行一个线程,它共享一个量子时间进行并行处理。

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 通过及时观察ThreadPoolExecutor ,我看到队列中有很多任务,在超时后,由于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. 当我使用具有双核处理器的设备时,Ping响应会降低。
  • 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)? 为什么队列中存在多个线程,每个线程大约需要10到50ms(增加线程时间会增加300ms或更多)?
  • 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. 我应该使用ConcurrentLinkedQueue但它使用生产者/消费者模型,不知何故ThreadPoolExecutor (我认为它)也使用这个模型。
  • LinkedBlockingQueue holds tasks before they executed (threads are idle or in queue), how to overcome this? LinkedBlockingQueue在执行任务之前保存任务(线程空闲或在队列中),如何克服这个问题?
  • By setting Thread.MAX_PRIORITY for latter iterations does't solve the problem (later iteration's thread are in queue) 通过为后面的迭代设置Thread.MAX_PRIORITY不能解决问题(后来的迭代的线程在队列中)
  • 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 添加5秒等额外时间不是解决方案
  • Changing corePoolSize like in How to get the ThreadPoolExecutor to increase threads to max before queueing? 更改corePoolSize就像如何让ThreadPoolExecutor在排队前将线程增加到最大值? 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. 当应用程序进入后台时,没有丢失,用户CPU使用率下降到0-2%,而焦点应用程序占用了4-6%的CPU使用率。 Is it due to UI and other ralted stuff, i tried to remove all unnecessary code also i did change PingThread to PingTask 是由于UI和其他ralted东西,我试图删除所有不必要的代码,我也改变PingThreadPingTask

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? 注意:我使用相同的代码创建了单独的基于java的应用程序,它在桌面上工作正常,所以我们可以说它是Android操作系统特定的问题吗?

I am not sure if this is what causes all the problems, but you are creating a lot of unnecessary threads. 我不确定这是否是导致所有问题的原因,但是你创造了许多不必要的线程。

You shoud replace 你应该替换

private class PingThread extends Thread {

with : 用:

private class PingThread implements Runnable {

or (using a more adequate name) : 或(使用更充分的名称):

private class PingTask implements Runnable {

ie the tasks submited to Executor s are not supposed to be thread themselves. 即提交给Executor的任务不应该是自己的线程。 It works, because a Thread implements Runnable , but you are wasting it. 它有效,因为一个Thread实现了Runnable ,但是你在浪费它。

Threads create a new unique object, while runnable allows all the threads to share one object. 线程创建一个新的唯一对象,而runnable允许所有线程共享一个对象。 As such, you should not extend Thread when trying to multithread, instead use Runnable: 因此,在尝试多线程时不应扩展Thread,而是使用Runnable:

class RunnableDemo implements Runnable {
    private Thread thread;
    String threadName="My thread";
    public void run() {
        //do your code from here 'logic'
        System.out.println("Threading is Running");
        try {
            for(int i = 4; i > 0; i--) {
                System.out.println("Thread: "+threadName +" "+ i);
                // Let the thread sleep for a while.
                Thread.sleep(50); //sleep your content for xx miliseconds
            }
        } catch (InterruptedException e) {
            System.out.println("Thread " +  threadName + " interrupted.");
        }
        System.out.println("Thread " +  threadName + " exiting.");
        //finish your work here 
    }

    public void start () {
        System.out.println("Starting " +  threadName );
        if (thread == null) {
            thread = new Thread (this);
            thread.start (); //This will call your run methods of Runnable
        }
    }
}
//test your thread from here
public class TestThread {
    public static void main(String args[]) {
        RunnableDemo R1 = new RunnableDemo( "Thread-1");
        R1.start();

        RunnableDemo R2 = new RunnableDemo( "Thread-2");
        R2.start();
    }   
}

Observation: 观察:

After creating and observing a independent java application (logs) using same code, I came to know the followings: 在使用相同的代码创建和观察独立的Java应用程序(日志)之后,我开始了解以下内容:

  • Somehow android OS architecture and/or processor is limiting the number of threads. 不知何故,android OS架构和/或处理器限制了线程数量。
  • LinkedBlockingQueue holds tasks before they executed, so if we have a long queue later threads in queue will have to wait more. LinkedBlockingQueue在执行任务之前保存任务,因此如果我们有一个长队列,队列中的线程将不得不等待更多。
  • Increase/Dynamic corePoolSize and maxPoolSize is doing the same, they added threads in queue 增加/动态corePoolSizemaxPoolSize也是这样,他们在队列中添加了线程
  • 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%. 应用程序使用4-6%的CPU,因此我们不能说CPU过载或使用完整的应用程序资源但是当应用程序进入后台(GUI或其他相关的OS和/或基于应用程序的线程可能停止或中断)时CPU使用率降至0 -3%。

Solution: 解:

For 50 iterations and 10 inner creates 500 threads now i did two things: 对于50次迭代和10次内部创建500个线程,我现在做了两件事:

  • Increase Thread.sleep(millis) time with some calculation involves. 通过一些计算涉及增加Thread.sleep(millis)时间。
  • 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 ie 3 * 3 = 9 remains 1 so we will create a separate thread for last request. 我正在创建10个线程,现在Math.ceil((double) 10 / 3) = 3 PingUtils.executePingRequest(pingRequest) Math.ceil((double) 10 / 3) = 3所以我们为每个线程有3个连续的PingUtils.executePingRequest(pingRequest) ,即3 * 3 = 9仍为1所以我们将为last创建一个单独的线程请求。 For each iteration instead of creating 10 threads now i am creating 4 threads. 对于每次迭代而不是现在创建10个线程我创建了4个线程。
  • Using this approach now i have 200 threads instead of 500 which solves the issue. 使用这种方法现在我有200个线程而不是500个解决了这个问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM