Android一个APP里面最少有几个线程

Android一个APP里面最少有几个线程

参考

https://www.jianshu.com/p/92bff8d6282f
https://www.jianshu.com/p/8a820d93c6aa

线程查看

Android一个进程里面最少包含5个线程,分别为:

  1. main线程(主线程)
  2. FinalizerDaemon线程
    终结者守护线程。对于重写了成员函数finalize的对象,它们被GC决定回收时,并没有马上被回收,而是被放入到一个队列中,等待FinalizerDaemon守护线程去调用它们的成员函数finalize,然后再被回收。
  3. FinalizerWatchdogDaemon线程
    监控终结者守护线程。用来监控FinalizerDaemon线程的执行。一旦检测那些重定了成员函数finalize的对象在执行成员函数finalize时超出一定的时候,那么就会退出VM。
  4. HeapTaskDaemon线程
    堆栈守护线程。用来执行堆栈的操作,也就是用来将那些空闲的堆内存归还给系统。
  5. ReferenceQueueDaemon线程。
    引用队列守护线程。我们知道,在创建引用对象的时候,可以关联一个队列。当被引用对象引用的对象被GC回收的时候,被引用对象就会被加入到其创建时关联的队列去。这个加入队列的操作就是由ReferenceQueueDaemon守护线程来完成的。这样应用程序就可以知道哪些被引用对象引用的对象已经被回收了。

下图是创建的一个仅有hello World!页面的工程,线程包含以下的这些。

在这里插入图片描述

刚开始我比较疑惑的是FileObserver 这个线程是否也是每个进程所必须包含的线程。后来我查看了一下Daemons创建的过程,能确定的是Android启动一个APP最少包含ReferenceQueueDaemon线程、FinalizerDaemon线程、FinalizerWatchdogDaemon线程、HeapTaskDaemon线程,以及在ActivityThread中开启的主线程。如下:

public final class Daemons {
    private static final int NANOS_PER_MILLI = 1000 * 1000;
    private static final int NANOS_PER_SECOND = NANOS_PER_MILLI * 1000;
    private static final long MAX_FINALIZE_NANOS = 10L * NANOS_PER_SECOND;

    public static void start() {
        ReferenceQueueDaemon.INSTANCE.start();//开启ReferenceQueueDaemon线程
        FinalizerDaemon.INSTANCE.start();//开启FinalizerDaemon线程
        FinalizerWatchdogDaemon.INSTANCE.start();//开启FinalizerWatchdogDaemon线程
        HeapTaskDaemon.INSTANCE.start();//开启HeapTaskDaemon线程
    }

    public static void startPostZygoteFork() {
        ReferenceQueueDaemon.INSTANCE.startPostZygoteFork();
        FinalizerDaemon.INSTANCE.startPostZygoteFork();
        FinalizerWatchdogDaemon.INSTANCE.startPostZygoteFork();
        HeapTaskDaemon.INSTANCE.startPostZygoteFork();
    }

    public static void stop() {
        HeapTaskDaemon.INSTANCE.stop();
        ReferenceQueueDaemon.INSTANCE.stop();
        FinalizerDaemon.INSTANCE.stop();
        FinalizerWatchdogDaemon.INSTANCE.stop();
    }
    ...
}

1.main线程

2. ReferenceQueueDaemon线程。

代码块

3. FinalizerDaemon线程

    private static class FinalizerDaemon extends Daemon {
        private static final FinalizerDaemon INSTANCE = new FinalizerDaemon();
        private final ReferenceQueue<Object> queue = FinalizerReference.queue;
        private final AtomicInteger progressCounter = new AtomicInteger(0);
        // Object (not reference!) being finalized. Accesses may race!
        private Object finalizingObject = null;

        FinalizerDaemon() {
            super("FinalizerDaemon");
        }

        @Override public void runInternal() {
            // This loop may be performance critical, since we need to keep up with mutator
            // generation of finalizable objects.
            // We minimize the amount of work we do per finalizable object. For example, we avoid
            // reading the current time here, since that involves a kernel call per object.  We
            // limit fast path communication with FinalizerWatchDogDaemon to what's unavoidable: A
            // non-volatile store to communicate the current finalizable object, e.g. for
            // reporting, and a release store (lazySet) to a counter.
            // We do stop the  FinalizerWatchDogDaemon if we have nothing to do for a
            // potentially extended period.  This prevents the device from waking up regularly
            // during idle times.

            // Local copy of progressCounter; saves a fence per increment on ARM and MIPS.
            int localProgressCounter = progressCounter.get();

            while (isRunning()) {
                try {
                    // Use non-blocking poll to avoid FinalizerWatchdogDaemon communication
                    // when busy.
                    FinalizerReference<?> finalizingReference = (FinalizerReference<?>)queue.poll();
                    if (finalizingReference != null) {
                        finalizingObject = finalizingReference.get();
                        progressCounter.lazySet(++localProgressCounter);
                    } else {
                        finalizingObject = null;
                        progressCounter.lazySet(++localProgressCounter);
                        // Slow path; block.
                        FinalizerWatchdogDaemon.INSTANCE.goToSleep();
                        finalizingReference = (FinalizerReference<?>)queue.remove();
                        finalizingObject = finalizingReference.get();
                        progressCounter.set(++localProgressCounter);
                        FinalizerWatchdogDaemon.INSTANCE.wakeUp();
                    }
                    doFinalize(finalizingReference);
                } catch (InterruptedException ignored) {
                } catch (OutOfMemoryError ignored) {
                }
            }
        }

        @FindBugsSuppressWarnings("FI_EXPLICIT_INVOCATION")
        private void doFinalize(FinalizerReference<?> reference) {
            FinalizerReference.remove(reference);
            Object object = reference.get();
            reference.clear();
            try {
                object.finalize();
            } catch (Throwable ex) {
                // The RI silently swallows these, but Android has always logged.
                System.logE("Uncaught exception thrown by finalizer", ex);
            } finally {
                // Done finalizing, stop holding the object as live.
                finalizingObject = null;
            }
        }
    }

4. FinalizerWatchdogDaemon线程

代码块

5. HeapTaskDaemon线程

private static class HeapTaskDaemon extends Daemon {
        private static final HeapTaskDaemon INSTANCE = new HeapTaskDaemon();

        HeapTaskDaemon() {
            super("HeapTaskDaemon");
        }

        // Overrides the Daemon.interupt method which is called from Daemons.stop.
        public synchronized void interrupt(Thread thread) {
            VMRuntime.getRuntime().stopHeapTaskProcessor();
        }

        @Override public void runInternal() {
            synchronized (this) {
                if (isRunning()) {
                  // Needs to be synchronized or else we there is a race condition where we start
                  // the thread, call stopHeapTaskProcessor before we start the heap task
                  // processor, resulting in a deadlock since startHeapTaskProcessor restarts it
                  // while the other thread is waiting in Daemons.stop().
                  VMRuntime.getRuntime().startHeapTaskProcessor();
                }
            }
            // This runs tasks until we are stopped and there is no more pending task.
            VMRuntime.getRuntime().runHeapTasks();
        }
    }

查看VMRuntime的源码发现 startHeapTaskProcessor()、runHeapTasks()均是native方法。

    public native void requestConcurrentGC();
    public native void concurrentGC();
    public native void requestHeapTrim();
    public native void trimHeap();
    public native void startHeapTaskProcessor();
    public native void stopHeapTaskProcessor();
    public native void runHeapTasks();

如何查看当前项目包含几个线程

在Android studio中点击Profile 图标,点击 CPU,显示如下图,点击 Record,然后再点击 Stop,即可生成。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/890079.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Golang | Leetcode Golang题解之第462题最小操作次数使数组元素相等II

题目&#xff1a; 题解&#xff1a; func partition(a []int, l, r int) int {x : a[r]i : l - 1for j : l; j < r; j {if a[j] < x {ia[i], a[j] a[j], a[i]}}a[i1], a[r] a[r], a[i1]return i 1 }func randomPartition(a []int, l, r int) int {i : rand.Intn(r-l1…

Android车载——VehicleHal运行流程(Android 11)

1 概述 本篇主要讲解VehicleHal的主要运行流程&#xff0c;包括设置属性、获取属性、订阅属性、取消订阅、持续上报属性订阅等。 2 获取属性流程 2.1 获取属性流程源码分析 作为服务注册到hwServiceManager中的类是VehicleHalManager&#xff0c;所以&#xff0c;CarServic…

【Qt】控件概述(2)—— 按钮类控件

控件概述&#xff08;2&#xff09; 1. PushButton2. RadioButton——单选按钮2.1 使用2.2 区分信号 clicked&#xff0c;clicked(bool)&#xff0c;pressed&#xff0c;released&#xff0c;toggled(bool)2.3 QButtonGroup分组 3. CheckBox——复选按钮 1. PushButton QPushB…

简单粗暴理解GNN、GCN、GAT

GNN 思想&#xff1a;近朱者赤近墨者黑 GNN的流程&#xff1a; 聚合&#xff08;把邻居的信息贴到自己身上来&#xff0c;作为它自己特征的补足&#xff09;更新循环&#xff08;为什么要多次&#xff1f;看以下例子&#xff09; GNN能干嘛&#xff1f; 1.结点分类&#xf…

动态规划lc

先找到规律&#xff0c;然后找边界情况&#xff1b;部分特殊情况分类讨论 *递归 70.爬楼梯 简单 提示 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢&#xff1f; 示例 1&#xff1a; 输入&#xff1a…

基于yolov8、yolov5的PCB板缺陷检测系统(含UI界面、数据集、训练好的模型、Python代码)

blog.csdnimg.cn/direct/6f53422ed9fd44dc8daad6dc5481c4c9.png) 项目介绍 项目中所用到的算法模型和数据集等信息如下&#xff1a; 算法模型&#xff1a;     yolov8、yolov8 SE注意力机制 或 yolov5、yolov5 SE注意力机制 &#xff0c; 直接提供最少两个训练好的模型…

第十八届 图像像素类型转化于归一

知识点&#xff1a;像素归一化 opencv中提供四种归一的方法 -NORM_MINMAX -NORM_INF -NORM_L1 -NORM_L2 最常用的就是NORM_MINMAX归一的方法 相关的API normalize&#xff1a;void normalize(InputArray src, OutputArray dst, double alpha 1, double beta 0, int n…

关于C语⾔内存函数 memcpy memmove memset memcmp

memcpy使⽤和模拟实现 void * memcpy ( void * destination, const void * source, size_t num ); 函数memcpy从source的位置开始向后复制num个字节的数据到destination指向的内存位置。 这个函数在遇到 \0 的时候并不会停下来。 如果source和destination有任何的重叠&am…

树莓派3b安装ubuntu18.04服务器系统server配置网线连接

下载ubuntu镜像网址 img镜像&#xff0c;即树莓派官方烧录器使用的镜像网址 ubuntu18.04-server&#xff1a;ARM/RaspberryPi - Ubuntu Wiki 其他版本&#xff1a;Index of /ubuntu/releases 下载后解压即可。 发现使用官方烧录器烧录配置时配置wifi无论如何都不能使用&am…

linux入门——“权限”

linux中有权限的概念&#xff0c;最常见的就是安装一些命令的时候需要输入sudo来提权&#xff0c;那么为什么要有这个东西呢&#xff1f; linux是一个多用户操作系统&#xff0c;很多东西看起来是有很多分&#xff0c;但是实际的存储只有一份&#xff08;比如命令&#xff0c;不…

小程序知识付费的优势 知识付费服务 知识付费平台 知识付费方法

在信息爆炸的时代&#xff0c;知识如同繁星点点&#xff0c;璀璨而散落。如何在这片知识的海洋中精准捕捞&#xff0c;成为现代人追求自我提升的迫切需求。小程序知识付费&#xff0c;正是这样一座桥梁&#xff0c;它以独特的优势&#xff0c;让智慧触手可及&#xff0c;轻触未…

【C++差分数组】P1672何时运输的饲料

本文涉及知识点 C差分数组 C算法&#xff1a;前缀和、前缀乘积、前缀异或的原理、源码及测试用例 包括课程视频 P1672何时运输的饲料 原文比较啰嗦&#xff0c;我简述一下&#xff1a; 第x天运来F1(1<F1<1e6)千克的饲料&#xff0c;第D&#xff08;1<2e3)天还剩F2&…

数论与同余 - 离散数学系列(七)

目录 1. 整数的性质 整除与因数 最大公约数与最小公倍数 2. 欧几里得算法 算法步骤 3. 模运算与同余 模运算 同余关系 同余的性质 4. 数论在密码学中的应用 RSA 加密算法 5. 实际应用场景 1. 数字签名 2. 哈希函数与数据完整性 3. 密钥交换 6. 例题与练习 例题…

单链表速通后续!

目录 1>>闲话 2>>头删 3>>查找 4>>在指定位置之前插入 5>>删除指定结点 6>>指定位置之后插入 7>>删除指定位置之后的结点 特别思考&#xff1a; 8>>销毁单链表 Slist.h Slist.c test.c 9>>总结 1>>闲话…

干货|SQL注入思路总结(非常详细)零基础入门到精通,收藏这一篇就够 了

1.SQL注入的业务场景及危害 1.1 什么是SQL注入 SQL注入是服务器端未严格校验客户端发送的数据&#xff0c;而导致服务端SQL语句被恶意修改并成功执行的行为称为SQL注入。 1.2 为什么会有SQL注入 代码对带入SQL语句的参数过滤不严格 未启用框架的安全配置&#xff0c;例如&a…

[面试] java开发面经-1

前言 目录 1.看到你的简历里说使用Redis缓存高频数据&#xff0c;说一下Redis的操作 2.说一下Redis的缓存击穿、缓存穿透、缓存雪崩 3.你的项目中使用了ThreadLocal&#xff0c;那么当有两个请求同时发出时&#xff0c;会怎么处理&#xff0c;可以同时处理两个请求吗 4.使用…

【多线程】多线程(12):多线程环境下使用哈希表

【多线程环境下使用哈希表&#xff08;重点掌握&#xff09;】 可以使用类&#xff1a;“ConcurrentHashMap” ★ConcurrentHashMap对比HashMap和Hashtable的优化点 1.优化了锁的粒度【最核心】 //Hashtable的加锁&#xff0c;就是直接给put&#xff0c;get等方法加上synch…

时间序列预测(一)——线性回归(linear regression)

目录 一、原理与目的 1、线性回归基于两个的假设&#xff1a; 2、线性回归的优缺点: 3、线性回归的主要目的是&#xff1a; 二、损失函数&#xff08;loss function&#xff09; 1、平方误差损失函数&#xff08;忽略了噪声误差&#xff09; 2、均方误差损失函数 三、随…

微服务实战——登录(普通登录、社交登录、SSO单点登录)

登录 1.1. 用户密码 PostMapping("/login")public String login(UserLoginVo vo, RedirectAttributes redirectAttributes, HttpSession session){R r memberFeignService.login(vo);if(r.getCode() 0){MemberRespVo data r.getData("data", new Type…

英伟达股价分析:英伟达股价能否上涨到150美元,接下来该如何操作?

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经​ 猛兽财经核心观点&#xff1a; &#xff08;1&#xff09;华尔街投行Oppenheimer已将英伟达的目标价上调到了150美元。 &#xff08;2&#xff09;产品方面的最新进展和合作伙伴关系进一步提升了英伟达的市场地位。 &…