当前位置: 首页 > 知识库问答 >
问题:

Java(Android)多线程进程

焦正德
2023-03-14

我正在开发应用程序(Matt的traceroute windows版本http://winmtr.net/),它创建了多线程,每个线程都有自己的进程(执行ping命令)。

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>()
);

平丝。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()
                );
        }
    }
}

现在如果我创建多个线程,比如在一个循环中超过500个线程,并在池执行器中执行

执行线程

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

我确实知道LinkedBlockingQueue在执行任务之前持有任务。每个线程的进程最多需要200到400ms,但通常小于10ms

我正在做的事

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次迭代将花费大约25秒,在这里,我只有40个ping响应,其余的考虑是由于超时造成的损失。如果我增加迭代次数,损失也会增加(由于线程数量的增加而呈指数增长)

观察:

我在Galaxy S6上运行这个应用程序,它有8个内核,应用程序池大小为16,最大池大小为16 2,我知道处理器一次只运行一个线程,它共享一个量子时间用于并行处理。

通过及时观察ThreadPoolExecator,我看到队列中有许多任务,超时后,由于LinkedBlockingQueue,队列中仍然有许多线程。

若我减少了线程数,那个么效果很好,但若我增加线程数,那个么就会产生问题

问题:

  • 当我使用具有双核处理器的设备时,ping响应会降低。
  • 为什么队列中存在许多线程,其中每个线程需要大约10到50ms(增加线程时间将增加uptp 300ms或更多)?
  • 它应该在给定的时间内完成,为什么不呢?
  • 如何克服这个问题?
  • 我是否应该使用ConexttLinkedQueue,但它使用了生产者/消费者模型,不知何故ThreadPoolExecator(我认为是)也使用了这个模型。
  • LinkedBlockingQueue在执行任务之前持有任务(线程空闲或在队列中),如何克服这一点?
  • 通过设置线程。后面迭代的MAX_PRIORITY不能解决问题(后面迭代的线程在队列中)
  • 减少没有线程解决问题为什么?因为队列中没有线程?
  • 有没有办法检查,如果队列中存在的线程娱乐它们,然后执行其他线程,而不阻塞其他线程,但在给定的时间内。
  • 增加额外的时间比如5秒不是解决办法
  • 更改corePoolsize,就像在如何让ThreadPoolExec导师在排队之前将线程增加到最大?在我的情况下不起作用。

在测试期间,内存和处理器的使用是有限制的。

需要详细的回答/帮助。

编辑

当应用程序进入后台时,没有损失,用户CPU使用率下降到0-2%,而在焦点应用程序中,CPU使用率下降了4-6%。是由于UI和其他ralted的东西,我试图删除所有不必要的代码,我也没有改变平线程平任务

PingTask实现可运行的{/*../}

注意:我使用相同的代码创建了单独的基于java的应用程序,它在桌面上运行良好,所以我们可以说这是android操作系统特有的问题吗?

共有3个答案

葛志国
2023-03-14

线程创建一个新的唯一对象,而runnable允许所有线程共享一个对象。因此,尝试多线程时不应扩展线程,而应使用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();
    }   
}
夹谷衡
2023-03-14

在创建和观察使用相同代码的独立java应用程序日志)后,我了解了以下内容:

  • 不知何故,Android操作系统架构和/或处理器限制了线程的数量。
  • LinkedBlockingQueue在执行任务之前持有任务,所以如果我们有一个很长的队列,队列中的线程将不得不等待更多。
  • 增加/动态corePoolsizemaxPoolsize正在做同样的事情,他们在队列中添加线程
  • 应用程序使用4-6%的CPU,所以我们不能说CPU超载或充分利用应用程序资源,但是当应用程序进入后台时(GUI或其他相关操作系统和/或基于应用程序的线程可能会停止或中断),CPU使用率下降到0-3%.

对于50次迭代和10次内部创建500个线程,现在我做了两件事:

  • 增加线程。睡眠(毫秒)需要计算的时间
  • 减少每次迭代的线程数。我现在正在创建10个线程Math。ceil((双精度)10/3)=3,因此我们有3个连续的pingutil。executePingRequest(pingRequest)对于每个线程,即3*3=9保持为1,因此我们将为最后一个请求创建一个单独的线程。对于每个迭代,我现在创建4个线程,而不是创建10个线程
  • 使用这种方法,我现在有200个线程,而不是500个线程,解决了这个问题

潘安平
2023-03-14

我不确定这是否是导致所有问题的原因,但您正在创建许多不必要的线程。

你应该换一个

private class PingThread extends Thread {

与:

private class PingThread implements Runnable {

或者(使用更合适的名称):

private class PingTask implements Runnable {

i、 e.提交给执行者的任务不应是线程本身。它可以工作,因为线程实现了可运行,但这是在浪费它。

 类似资料:
  • 多线程 多线程(multiple thread)是计算机实现多任务并行处理的一种方式。 在单线程情况下,计算机中存在一个控制权,并按照顺序依次执行指令。单线程好像是一个只有一个队长指挥的小队,整个小队同一个时间只能执行一个任务。 单线程 在多线程情境下,计算机中有多个控制权。多个控制权可以同时进行,每个控制权依次执行一系列的指令。多线程好像是一个小队中的成员同时执行不同的任务。 可参考Linux多

  • 除了隐式用户界面线程之外,我还制作了两个线程(可运行的),它们内部都有一个 while 循环,我定期检查我实现的消息队列中的更新。 一开始的问题是这两个while循环是无限的,它们变化得如此之快,如此之多,几乎耗尽了设备的所有CPU。所以我考虑让while循环在每个周期后Hibernate大约100毫秒,让其他线程完成它们的工作,但是我遇到了另一个问题: 现在,问题是线程Hibernate了100

  • 问题内容: 我正在阅读SašaJurić撰写的《行动中的长生不老药》,在第一章中说: Erlang进程彼此完全隔离。它们不共享内存,并且一个进程的崩溃不会导致其他进程的崩溃。 Java线程也不是真的吗?我的意思是,当Java线程崩溃时,它也不会崩溃其他线程- 尤其是,如果我们正在查看请求处理线程(请将该线程排除在此讨论之外) 问题答案: 在我之后重复: “这些是不同的范例” 大声说20次左右-这是

  • 本文向大家介绍Java多线程之多线程异常捕捉,包括了Java多线程之多线程异常捕捉的使用技巧和注意事项,需要的朋友参考一下   一:为什么要单独讲多线程的异常捕捉呢? 先看个例子:   在run中手动抛出了一个运行时异常,在main中启动线程,catch语句块中捕捉下异常,捕捉到打印一句话。运行结果如下图:   发现异常被抛到了控制台,没有打印catch块中的语句。   结论:多线程运行不能按照顺

  • 问题内容: 我有一个python应用程序,它可以捕获数据集合,并针对该集合中的每个数据执行任务。由于涉及到延迟,因此该任务需要一些时间才能完成。由于这种延迟,我不希望每个数据都随后执行任务,而是希望它们全部并行发生。我应该使用多进程吗?或执行此操作的线程? 我尝试使用线程,但遇到了一些麻烦,通常某些任务实际上不会执行。 问题答案: 如果您确实受到计算的限制,那么使用多处理模块可能是最轻巧的解决方案

  • 12.1.1 Windows 3.x的协同多任务 在16位的Windows 3.x中,应用程序具有对CPU的控制权。只有在调用了GetMessage、PeekMessage、WaitMessage或Yield后,程序才有可能把CPU控制权交给系统,系统再把控制权转交给别的应用程序。如果应用程序在长时间内无法调用上述四个函数之一,那么程序就一直独占CPU,系统会被挂起而无法接受用户的输入。 因此,在