59. 【Android教程】多线程

多线程可以让你同时异步执行多种任务,是各种编程语言里很重要的一个概念。合理的采用多线程可以让你的 App 拥有更好的运行性能,但是如果使用不当可能会让你的程序非常混乱,出现很多令人费解且难以定位的问题。

1. 多线程初探

当用户打开一个 App 时,Android 系统会创建一个 Linux 进程,同时在进程中创建一个执行线程,我们称之为“主线程”,因为 Andfoid 规定只能在主线程更新 UI,所以又叫“UI线程”。
系统在创建主线程的时候帮我们创建好了一套消息处理机制,包含了第 38 节提到的 Handler、Looper、MessageQueue 等模块,主线程就利用这一套消息机制来实现 Actvity、Fragment 的生命周期回调以及和其他 App 之间的通信。所有需要在 UI 线程执行的任务都要首先被 push 到任务队列中,然后等待主线程 Looper 来轮询。如果我们将所有的任务都放到主线程的任务队列,那么可能需要等很久才能执行到,所以一个比较好的选择就是将耗时任务单独放到一个子线程中,这样就可以独享一个 MessageQuene,并且不再占用主线程的资源。

2. 多线程注意事项

  • Android 规定刷新 UI 的操作必须在主线程执行;
  • 网络请求、数据库或者文件 I / O 等都属于耗时操作,非常容易导致主线程的阻塞造成 App 卡顿;
  • 由于主线程的 Looper 是按顺序轮询 MessageQueue 的,所以主线程的所有任务都是同步执行。这样如果有耗时操作那么会阻塞主线程,后面的任务都需要等待耗时操作的执行;
  • 除了 I / O 操作外,开发人员需要自行评估任务的耗时情况,合理采用多线程避免主线程的阻塞;
  • Android 提供了多种创建和管理线程的方法,当然如果有高并发的场景还有一些第三方库可以使用,但是系统的线程、线程池可以应对大部分常见场景。

接下来我们来看看具体怎么使用 Android 多线程。

3. 线程的使用方法

Java 虚拟机支持多线程并发编程,并发意味着同时执行多个任务。在 Android 中常见的多线程常见就是在子线程执行耗时操作,然后将结果通过线程间通信传递给主线程,主线程仅仅拿到结果进行 UI 的刷新。

3.1 线程的创建

我们有两种方式进行线程的创建

  1. 继承Thread实现一个线程类:
class TestThread extends Thread {@Overridepublic void run() {Log.d("Threading", "继承 Thread 的线程:"+Thread.currentThread().getName());}
}
  1. 实现Runnable接口
class TestRunnable implements Runnable {@Overridepublic void run() {Log.d("Runable", "实现 Runable 的线程>"+Thread.currentThread().getName());}
}

无论是哪种方式,都需要在类中实现一个无参的run()方法,然后将线程的实际执行任务放在run()方法中,在要用多线程的类中需要创建出一个Runnable接口实例。

3.2 启动进程

对于第一种创建方式,直接创建 TestThread 实例调用start()即可:

new TestThread().start()

而对于第二种方式,在创建 Thread 的同时传入 Runnable 接口实例,然后调用start()

new Thread(new TestRunnable()).start()

调用了 Thread 对象的 start()之后,run()方法就会在我们的子线程中执行了。

3.3 线程生命周期

和 Activity 一样,Thread 在执行过程中也有自己的生命周期,一共有 5 种状态:

  • **New:**刚创建好,还未执行
  • **Runnable:**已经调用了start(),等待 CPU 分配时间片
  • **Running:**正在运行
  • **Blocked:**由于某些原因(等待、睡眠、CPU暂时回收资源等)线程进入阻塞
  • **Dead:**线程任务执行结束,或者主动关闭

各个生命周期的切换如下图:

4. 多线程示例

本节创建两个耗时子线程,在线程的开始和结束分别打上日志,然后观察两个线程任务是同时执行,还是需要等待其中一个线程的耗时任务执行结束才能执行第二个。
MainActivity 代码很简单,在里面创建两个线程,为了方便演示我们用“继承自 Thread”和“实现 Runnable”两种方式来创建两个线程:


package com.emercy.myapplication;import android.app.Activity;
import android.content.pm.PackageManager;
import android.media.MediaPlayer;
import android.media.MediaRecorder;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;import androidx.annotation.Nullable;import java.io.IOException;
import java.util.Random;import static android.Manifest.permission.RECORD_AUDIO;
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;public class MainActivity extends Activity {@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);new Thread() {@Overridepublic void run() {Log.d("ThreadTest", "Thread1 start");try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}Log.d("ThreadTest", "Thread1 end");}}.start();new Thread(new Runnable() {@Overridepublic void run() {Log.d("ThreadTest", "Thread2 start");try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}Log.d("ThreadTest", "Thread2 end");}}).start();}private void task() {for (int i = 0; i < 10; i++) {Log.d("Thread", Thread.currentThread().getName() + " 当前i = " + i);}}
}

在两个线程中通过sleep()来模拟 500 毫秒的耗时任务,在任务的开始和结束都打上日志,观察结果如下:

可以看到首先会同时开启两个子线程,然后分别同时执行 500 毫秒的任务,在执行结束打上结束的 Log,可以证明两个 Thread 是同时执行的。

5. 小结

本节学习了一个能让你的 App 并发高效执行任务的方式,多线程可以帮助你提升 App 的整体性能,但用之不当可能会造成一定的资源浪费,所以一定要谨记本节所提到的注意事项。然后按照步骤去创建、运行子线程,了解线程执行的生命周期,让程序更好的为用户服务。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python+pycharm安装教程

介绍 Python提供了高效的高级数据结构&#xff0c;还能简单有效地面向对象编程。Python语法和动态类型&#xff0c;以及解释型语言的本质&#xff0c;使它成为多数平台上写脚本和快速开发应用的编程语言&#xff0c;Python解释器易于扩展&#xff0c;可以使用C、C或其他可以通过…

企业为什么要自己搭建企业邮箱?

近年来&#xff0c;随着企业信息化建设的加速&#xff0c;企业邮箱在企业的对外沟通和对内管理过程中发挥着重要作用&#xff0c;已经成为企业使用频次高的办公应用之一。然而&#xff0c;随着企业邮箱的广泛应用以及所产生的数据越来越多&#xff0c;也为企业的运营带来了巨大…

【excel】数据非数值导致排序失效

场景 存在待排序列的数值列&#xff0c;但排序失效&#xff0c;提示类型有问题&#xff1a; 解决 选中该列&#xff0c;数据→分列 而后发现提示消失&#xff0c;识别为数字&#xff0c;可正常排序。

地下水位自动监测设备:矿井水文监测系统

TH-DSW2地下水位自动监测设备具有实时性、连续性和自动化等特点&#xff0c;广泛应用于地下水深井水位测量、矿山深井水位测量、地热井水位测量。可以实现对地下水位的24小时不间断监测。它在城市供水和水资源管理、农业灌溉、地质和地下探测等领域具有广泛的应用。 在城市供水…

kali下Nessus漏扫工具的安装-超级详细

Nessus的安装 下载软件地址&#xff1a;https://www.tenable.com/downloads/nessus?loginAttemptedtrue 1、拷贝软件包到kali家目录下 2、使用root用户进行解压 ┌──(kali㉿kali)-[~/桌面] └─$ sudo -i #切换管理员root [sudo] kali 的密码&#xff1a; #移动软件到…

​「Python绘图」绘制太极图

python 绘制太极 一、预期结果 二、核心代码 import turtlepen turtle.Turtle()print("开始绘制太极")radius 100 pen.color("black", "black") pen.begin_fill() pen.circle(radius/2, 180) pen.circle(radius, 180) pen.left(180) pen.circ…

nginx--系统参数优化telenct

系统参数 在生产环境中&#xff0c;根据自己的需求在/etc/sysctl.conf来更改内核参数 net.ipv4.ip_nonlocal_bind 1 允许非本地IP地址socket监听 net.ipv4.ip_forward 1 开启IPv4转发 net.ipv4.tcp_timestamps 0 是否开启数据包时间戳 net.ipv4.tcp_tw_reuse 0 端⼝口复⽤…

影响视频视觉质量的因素——各类视觉伪影

模糊效应&#xff08;Blurring Artifact&#xff09; 图像模糊&#xff08;blurring&#xff09;&#xff1a;平滑图像的细节和边缘产生的现象&#xff0c;模糊对于图像来说&#xff0c;是一个低通滤波器&#xff08;low-pass filter&#xff09;。一般而言&#xff0c;用户更…

JavaEE概述 + Maven

文章目录 一、JavaEE 概述二、工具 --- Maven2.1 Maven功能 仓库 坐标2.2 Maven之项目构建2.3 Maven之依赖管理 三、插件 --- Maven Helper 一、JavaEE 概述 Java SE、JavaEE&#xff1a; Java SE&#xff1a;指Java标准版&#xff0c;适用于各行各业&#xff0c;主要是Java…

九州金榜|如果孩子胆小懦弱,如何家庭教育?

在孩子成长的过程中&#xff0c;孩子可能会出现胆小懦弱的表现&#xff0c;当孩子出现这个问题是&#xff0c;势必会对孩子成长造成影响&#xff0c;可能会影响孩子的社交&#xff0c;学习以及日常生活等。对此很多家长不明白哪地方出现了问题&#xff0c;就会着急。面对这种情…

如何提取下载51cto上的视频

掌握在手中的视频资源&#xff0c;让学习更高效&#xff01;想要轻松从51cto上提取并下载视频吗&#xff1f;只需要用到一个工具&#xff0c;让你轻松下载51cto上的视频 下载51cto的工具我已经打包好了&#xff0c;有需要的自己下载 下载51cto工具打包链接&#xff1a;百度网…

嵌入式C语言高级教程:实现基于STM32的自适应交通信号控制系统

自适应交通信号控制系统能够基于实时交通流数据调整信号灯的时长&#xff0c;提高路口的通行效率。本教程将指导您如何在STM32微控制器上实现一个基本的自适应交通信号控制系统。 一、开发环境准备 硬件要求 微控制器&#xff1a;STM32F103C8&#xff0c;具备足够的处理能力…