Android 多线程编程初探

Android多线程编程:Handler与Looper 本文详细阐述了Android多线程编程中Handler与Looper的基本原理、使用方法及其在异步消息处理和定时任务中的应用。通过正确使用Handler与Looper,开发者可以在子线程中执行耗时操作,而在主线程中更新UI,从而提高应用程序的响应速度和用户体验。在未来,随着Android技术的发展,Handler与Looper可能会出现更多新的用法和优化。开发者应不断学习和掌握新的技术,以提高自己的编程水平。同时,本文也希望能够为读者提供一些有价值的信息和启示,助力Android开发者的成长。 阅读详情

       Android 中的多线程其实就是 java SE 中的多线程,只是为了方便使用,Android 封装了一些类,如 AsyncTask、HandlerThread 等,在日常的开发过程中,我们往往需要去执行一些耗时的操作,例如发起网络请求,考虑到网速等其他外在的因素,服务器可能不会立刻响应我们的请求,如果不将这条操作放到子线程中去执行,就会造成主线程被阻塞,今天我们就从多线程的基础来一起探讨,来概览今天的内容




一、线程的基本用法


对于 Andorid 多线程来说我们最新接触到的就是 Thread 和 Runnable 通常我们如下来启动一个新的线程


1)继承自 Thread 来创建子线程


定义一个线程只需要新建一个类继承自 Thread,然后重写父类的 run 方法即可

    /**
     * 继承 Thread 创建子线程
     */
    class MyThread extends Thread {
        @Override
        public void run() {
            //处理具体的逻辑
        }
    }

那么如何启动这个线程呢?只需要 new 出 MyThread 的实例,然后调用它的 start() 方法,这样 run() 方法中的代码就会运行在子线程,如下:

    new MyThread().start();

2)实现 Runnable 接口来创建子线程

继承方式耦合性高,更多时候我们会选择实现 Runnable 接口的方式来实现一个子线程,如下:

    /**
     * 实现 Runnable 接口创建子线程
     */
    class MyThread implements Runnable {
        @Override
        public void run() {
            //处理具体的逻辑
        }
    }

如果使用这种写法,启动线程的方法也需要相应的改变,如下:

        MyThread myThread = new MyThread();
        new Thread(myThread).start();

Thread 构造函数接受一个 Runnable 参数,我们 new 出的 MyThread 正是一个实现了 Runnable 接口的对象,所以可以直接将它传入到 Thread 的构造函数里,接着就和上面的一样了,调用 Thread 的 start() 方法,run() 方法中的代码就会在子线程当中运行了


3)直接使用匿名类来创建子线程


        new Thread(new Runnable() {
            @Override
            public void run() {
                //处理具体的逻辑
            }
        }).start();

如果你不想再定义一个类去实现 Runnable 接口,也可以使用如上匿名类的方式来实现,这种实现方式也是我们最常用到的

以上这些就是我们来创建子线程时使用的不方式,基本和 Java 中一样


4)Thread 和 Runnable 的区别


       实际上 Thread 也是一个 Runnable,它实现了 Runnable 接口,在Thread类中有一个 Runnable 类型的 target字段,代表要被执行在这个子线程中的任务,代码如下:

Thread 部分源码:

public class Thread implements Runnable {
    /* What will be run. */
    private Runnable target;
    /* The group of this thread */
    private ThreadGroup group;

    private String name;
    /*
   * The requested stack size for this thread, or 0 if the creator did
   * not specify a stack size.  It is up to the VM to do whatever it
   * likes with this number; some VMs will ignore it.
   */
    private long stackSize;

    /**
     * 初始化 Thread 并且将Thread 添加到 ThreadGroup 中
     *
     * @param g
     * @param target
     * @param name
     * @param stackSize
     */
    private void init(ThreadGroup g, Runnable target, String name, long stackSize) {
        java.lang.Thread parent = currentThread();
        //group 参数为空,则获取当前线程的才线程组
        if (g == null) {
            g = parent.getThreadGroup();
        }
        this.group = g;
        this.name = name;
        //设置 target
        this.target = target;
        /* Stash the specified stack size in case the VM cares */
        this.stackSize = stackSize;
    }

    public Thread() {
        init(null, null, null, 0);
    }

    public Thread(Runnable target) {
        init(null, target, null, 0);
    }

    public Thread(ThreadGroup group, Runnable target) {
        init(group, target, null, 0);
    }

    public Thread(Runnable target, String name) {
        init(null, target, name, 0);
    }

    public Thread(ThreadGroup group, Runnable target, String name) {
        init(group, target, name, 0);
    }

    public Thread(ThreadGroup group, Runnable target, String name,
                  long stackSize) {
        init(group, target, name, stackSize);
    }

    /**
     * 启动一个新的线程,如果target 不为空则执行 target 的 run 函数
     * 否者执行当前对象的run()方法
     */
    public synchronized void start() {
        //调用 nativeCreate 启动新线程
        nativeCreate(this, stackSize, daemon);
        started = true;
    }

    @Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }
}

      上面是 Thread 的部分源码,我们看到其实 Thread 也实现了 Runnable 接口,最终被线程执行的是 Runnable,而非 Thread,Thread 只是对 Runnable 的包装,并且通过一些状态对 Thread 进行管理与调度,Runnable 定义了可执行的任务它只有一个无返回值的 run() 函数,如下:

    public interface Runnable {
        /**
         * When an object implementing interface <code>Runnable</code> is used
         * to create a thread, starting the thread causes the object's
         * <code>run</code> method to be called in that separately executing
         * thread.
         * <p>
         * The general contract of the method <code>run</code> is that it may
         * take any action whatsoever.
         *
         * @see java.lang.Thread#run()
         */
        public abstract void run();
    }

当启动一个线程时,如果 Thread 的 Target 不为空时,则会在子线程中执行这个 target 的 run() 函数,否则虚拟机就会执行该线程自身的 run() 函数


二、线程的 wait、sleep、join、yield


       Thread 的基本用法相对来说比较简单,通常就是复写 run() 函数,然后调用线程的 start() 方法启动线程,接下来我们来看看 wait、sleep、join、yield 的区别

1)wait

       当一个线程执行到 wait() 方法时,它就进入到一个和该对象相关的等待池中,同时释放对象的机锁,使得其它线程可以访问,用户可以使用 notify、nitifyAll 或者指定睡眠时间来唤醒当前等待池中的线程,注意:wait()、notify()、notifyAll() 必须放在 Synchronized 块中,否则会抛出异常

2)sleep

       该函数是 Thread 的静态函数,作用是使调用线程进入睡眠状态,因为 sleep() 是 Thread 类的静态方法,因此它不能改变对象锁,所以当在一个 Synchronized 块中调用 sleep() 方法时,线程虽然休眠了,但是对象的锁并没有被释放,其它线程无法访问这个对象,即使睡眠也持有对象的锁

3)join

等待目标线程执行完之后再继续执行

4)yield

线程礼让,目标线程由运行状态转换为就绪状态,也就是让出执行权限,让其它线程可以优先执行,但其他线程能否优先执行未知


三、线程池


       当我们需要频繁的创建多个线程进行耗时操作时,每次都经过 new Thread 实现并不是一种好的方式,每次 new Thread 新建和销毁对象的性能较差,线程缺乏统一管理,可能无限制新建线程,相互之间竞争,可能占用过多系统资源导致死锁,并且缺乏定时执行,定期执行,线程中断等功能,Java 提供了 4 种线程池,它能够有效的管理,调度线程,避免过多的浪费系统资源,它的优点如下:


1)重用存在的线程,减少对象创建,销毁的开销

2)可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多的资源竞争,避免堵塞

3)提供定时执行、定期执行、单线程、并发数控制等功能


       简单来说,线程池原理简单的解释就是会创建多个线程并进行管理,提交给线程的任务会被线程池指派给其中的线程进行执行,通过线程池的统一调度、管理使得多线程使用更加简单、高效,如下图:


       线程池都实现了 ExecutorService 接口,改接口定义了线程池需要实现的接口,它的实现有  ThreadPoolExecutor 和 ScheduledThreadPoolExecutor,ThreadPoolExecutor 也就是我们运用最多的线程池实现,ScheduledThreadPoolExecutor 用于周期性执行任务,通常我们都不会直接通过 new 的形式来创建线程池,由于创建参数过程相对复杂一些,因此 JDK 给我们提供了一个 Executor 工厂类来简化这个过程


线程池的使用准则:

1)不要对那些同步等待的其他任务结果的任务排队,这可能会导致死锁,在死锁中所有所有线程都被一些任务所占用,这些任务依次等待排队任务的结果,而这些任务又无法执行,因为所有的线程处于忙碌状态

2)理解任务,要有效的调整线程池的大小,你需要理解正在排队的任务以及它们正在做什么

3)调整线程池的大小基本上就是避免两类错误,线程太少或线程太多,幸运的是对于大多数应用程序来说,太多和太少之间的余地相当宽


今天介绍的基本都是一些理论的东西,有的看起来可能没劲,大家就当了解一下吧,又到周五了,祝大家周末愉快


参考:郭神第一行代码,Android 进阶



【Android面试八股文】sleep、wáit、yield与join的区别,wait 的线程如何唤醒它? 在 Java 多线程编程中,sleepwaityield和join是四个常用的方法,它们在控制线程行为方面各有不同的用途。以下是它们之间的区别以及wait。 阅读详情

相关推荐

华为防火墙NAT避坑指南:当双ISP出口遇到服务器发布,这些细节不注意会翻车

本文深入解析华为防火墙在双ISP出口环境下服务器发布的实战配置,重点探讨no-reverse参数对Server-Map表的影响、源进源出功能的实现及线路切换时的会话保持问题。通过策略路由和智能选路技术,确保HTTP/FTP服务在多运营商链路中的高可用性,避免路径不对称和NAT映射冲突等常见陷阱。

weixin_30897233的博客 550

Java多线程之sleep,wait,join和yield关键字,以及线程的关闭

在java或者android中,使用Thread和Runnable就可以玩多线程了,这个成本比较低,也没什么好说的,今天主要是针对多线程中主要的关键字wait,sleep,join和yield做个笔记,加强一下印象。wait  wait方法一般都是和notity()或者notifyAll()成对出现的。当某个线程执行到wait()方法时,它就进入到一个和该对象相关的等待池中,同时失去了对象的锁功能,

成长的烧年 3022

稀疏阵列选型指南:互质阵、嵌套阵、MRA,谁才是你项目里的‘性价比之王’?

本文深入探讨了稀疏阵列技术中的互质阵、嵌套阵和MRA三大架构的工程化选型策略,重点分析了它们在DOA估计、自由度、旁瓣抑制和计算复杂度等核心指标上的表现。通过实际案例和配置示例,为智能天线、声学定位和毫米波雷达等应用场景提供技术选型指南,帮助研发团队在硬件成本与性能之间找到最佳平衡点。

weixin_42525005的博客 488

浅谈sleep、wait、yield、join区别

sleep sleep 方法是属于Thread 类中的,sleep 过程中线程不会释放锁,只会阻塞线程,让出cpu给其他线程,但是他的监控状态依然保持着,当指定的时间到了又会自动恢复运行状态,可中断,sleep 给其他线程运行机会时不考虑线程的优先级,因此会给低优先级的线程以运行的机会 示例代码: /** * 线程sleep测试 * * @author supu * @date ...

大龙的博客 2万+

GMSL2摄像头接入避坑指南:从FMC子卡配置到V4L2调用的完整流程(附Ubuntu20.04实测)

本文详细解析了GMSL2摄像头接入的全流程,从FMC子卡配置到V4L2调用的完整指南。基于XC7Z100平台实测经验,提供了硬件选型、带宽优化、Linux驱动配置及高分辨率采集的实战技巧,帮助开发者规避常见问题,提升系统稳定性与性能。

weixin_33737774的博客 418

人工势场法在自动驾驶避障中的实践与优化

本文深入探讨了人工势场法在自动驾驶避障中的核心原理与实践优化。通过解析引力与斥力模型,揭示了经典算法在局部最优和目标不可达等问题上的局限性,并重点介绍了改进斥力场函数、引入道路边界斥力及动态参数调整等关键优化策略,有效提升了该局部路径规划算法在复杂动态场景下的实用性与鲁棒性。

weixin_29208327的博客 927

Android进阶——多线程系列之wait、notify、sleep、join、yield、synchronized关键字、ReentrantLock锁

前言 多线程一直是初学者最困惑的地方,每次看到一篇文章,觉得很有难度,就马上叉掉,不看了,我以前也是这样过来的。后来,我发现这样的态度不行,知难而退,永远进步不了。于是,我狠下心来看完别人的博客,尽管很难但还是咬着牙,不懂去查阅资料,到最后弄懂整个过程。虽然花费时间很大,但这就是自学的精髓,别人学不会,而我却学到了。很简单的一个例子,一开始我对自定义View也是很抵触,看到很难的图就不去思考他,

点击置顶文章查看博客目录(全站式导航) 1万+

使用Docker搭建SearXNG搜索引擎

【代码】使用Docker搭建SearXNG搜索引擎。

janthinasnail的博客 1168

Java中join和yield的作用

本文来自http://blog.youkuaiyun.com/liuxian13183/,引用必须注明出处! 1、 A.join,在API中的解释是,堵塞当前线程B,直到A执行完毕并死掉,再执行B。 用一个小例子来说明吧 static class ThreadA extends Thread { @Override public void run() { /

劝学 5987

第一节:初识n8n与下一代工作流自动化

本章介绍了n8n的Fair-code理念与节点式架构,对比了其与Zapier/Make的核心差异,并引导读者在n8n Cloud上完成首次界面导览,建立了工作流自动化的宏观认知。

easeyoo的专栏 106

数据权限设计

随着IT新技术不断完善成熟,企业数字化建设得到全面的发展,数据将成为一个创造财富的重要来源,并且越来越多地被视为一项值得重视的企业资产。未来,很多企业之间的竞争,其实也是资源和数据竞争。那么针对数据资产,如何保障它的安全性呢?数据的权限管理无疑是必不可少的。数据权限从数据源来控制不同的用户能够查看、使用和授权不同的数据表数据(其实就是数据表行列的管控),就如同筑起了一道道护城墙,为数据安全提供了保障。

qq_40664711的博客 1万+

android的多线程代码,Android 多线程编程初探(示例代码)

Android中的多线程其实就是JavaSE 中的多线程,只是为了方便使用,android封装了一些类,如 AsyncTask、HandlerThread 等,在日常的开发过程中,我们往往需要去执行一些耗时的操作,例如发起网络请求,考虑到网速等其他外在的因素,服务器可能不会立刻响应我们的请求,如果不将这条操作放到子线程中去执行,就会造成主线程被阻塞,今天我们就从多线程的基础来一起探讨一、线程...

weixin_39652154的博客 238

PCL 三次均匀B样条曲线拟合

PCL 三次均匀B样条曲线拟合

dayuhaitang1的博客 402

android学习笔记——android多线程编程初探

在本篇文章中将会介绍到的内容有: 1.介绍多线程用处 2.线程的基本用法 3.简单讲解异步消息处理机制(用于更新UI) 1.多线程 当我们需要执行一些耗时操作时,如果单纯的将耗时操作交给主线程去做,那么有可能别的一些更需要主线程做的任务就被耽搁了(如UI的更新),导致了主线程被阻塞,影响了用户对软件的正常使用。所以需要将一些耗时的操作分配给子线程去做,提高软件的友好性。

雅文的专栏 436

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

安卓app开发系列之-多线程编程

多线程编程是提高Android应用性能和用户体验的关键。本文介绍了Android中实现多线程的方法,包括基本的线程管理类和高效的线程池方式,以及现代Kotlin协程的使用。尽管多线程编程为开发带来了好处,但也引入了复杂性,需要开发者特别注意竞争条件、内存泄漏等问题。随着对多线程技术的深入理解,开发者能够更有效地管理应用行为,以提升用户的满意度和应用的性能。如果有进一步的问题或需要探讨的内容,请随时提出!

Jamson 1368

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

Android多线程编程

Android的UI是线程不安全的。即,如果想要更新应用程序里的UI元素,必须在主线程中进行,否则就会出现异常。但是如果我们想在主线程中开一个子线程来执行一些耗时操作(比如网络请求等),在Android中该怎么做呢?这个时候就要用到handler的消息机制了。

penghc的博客 1347

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

深度分析Android多线程编程

深度掌握 Android 多线程编程是一个持续学习和实践的过程。理解不同方案的原理、优缺点和适用场景,并遵循最佳实践,才能构建出既高效又健壮的 Android 应用。为了解决主线程瓶颈,必须将耗时操作转移到后台线程执行,完成后根据需要将结果安全地传回主线程更新 UI。理解并正确运用多线程是构建高性能、流畅、响应迅速的 Android 应用的关键,但也充满挑战和陷阱。

JMY_2016的博客 1054

Android 之 多线程编程

Android多线程编程核心要点: 线程模型: 主线程处理UI交互,禁止耗时操作(5秒ANR限制) 工作线程执行网络请求、文件IO等耗时任务 实现方案: 基础Thread/Runnable(简单但开销大) Handler/Looper(线程通信传统方案) 线程池(复用线程,推荐Fixed/Cached/Scheduled) 协程(轻量级,结构化并发,自动生命周期管理) 线程通信: Handler/Looper传统方式 LiveData/Flow自动线程切换 协程通道支持背压处理 优化建议: 注意线程安全(同

早日成为鹏总 1136

Android 多线程编程

在Android中,我们绘制图形界面的线程即是主线程,也叫UI线程,由于在主线程中进行过于耗时的操作

superxlcr的博客 804

安卓服务与多线程

OverrideLog.d(TAG, "服务创建了");// 初始化操作@OverrideLog.d(TAG, "服务启动了");// 执行后台任务@OverrideLog.d(TAG, "服务销毁了");// 释放资源@Override// 返回Binder对象用于Activity与Service通信服务:适合执行后台任务,但需要注意生命周期管理和资源释放多线程:Android UI操作必须在主线程执行,耗时操作应在子线程执行通信机制。

2401_86909484的博客 753

android网络编程多线程,安卓网络编程实例

在实验的安卓界面完成后,下一步就是对接后台了。在实际的应用中,通常需要从后台接口中获取或修改数据库数据,展示在安卓界面中。为了完成这样的功能,学习了安卓的网络编程实例。使用网络获取数据使用网络技术也很简单,无非是发送http请求并解析返回数据,在这里使用了android的网络通信库OkHttp,它能更加简化网络请求的步骤。首先在app/build.gradle文件中声明OkHttp依赖:imple...

weixin_29557457的博客 528

Android多线程实现的几种方式_安卓多线程

目前已经更新的部分资料:网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。需要这份系统化学习资料的朋友,可以戳这里获取一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**需要这份系统化学习资料的朋友,可以戳这里获取。

erhtre的博客 633

Android——多线程编程

Android简单的多线程编程

weixin_62654344的博客 358

【安卓】多线程编程

注意,在这个方法中是不可以进行UI操作的。Looper:Looper是每个线程中的MessageQueue的管家,调用Looper的loop()方法后,就会进入一个无限循环当中,然后每当发现MessageQueue中存在一条消息时,就会将它取出,并传递到Handler的handleMessage()方法中。发送消息一般是使用Handler的sendMessage()方法、post()方法等,而发出的消息经过一系列地辗转处理后,最终会传递到Handler的handleMessage()方法中。

君子慎独,不欺暗室。卑以自牧,含章可贞。 726
上一篇: Android 四大组件之 Service (下)
下一篇: Android 四大组件之 BroadcastReceiver
QDJdeveloper
博客等级 码龄11年 108粉丝 49原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值