Android多线程学习:线程

一、概念

进程:系统资源分配的基本单位,进程之间相互独立,不能直接访问其他进程的地址空间。

线程:CPU调度的基本单位,线程之间共享所在进程的资源,包括共享内存,公有数据,全局变量等。

后台线程:后台线程又称为守护线程(Daemon Thread),JVM的垃圾回收线程就是典型的后台线程。

举例记忆:以下纯属本人瞎编,方便记忆

  • 进程就是一个鞋子工厂,鞋子由鞋带、鞋底、鞋帮三部分组成。线程就是工厂下的流水线,一条流水线做鞋带,一条流水线做鞋底,一条流水线做鞋帮,最后再把做好的组件组装起来变成一个鞋子。
  • 我们会把原材料直接提供给工厂,工厂统一接收而不是里面具体的某个流水线。所以工厂(进程)就是我们系统分配资源的最小单位。
  • 如果想做出鞋子,至少要开启一个流水线工作,这个流水线可以先做鞋带,在做鞋帮,在做鞋底,最后再组装成鞋子,如果没有流水线工作,一双鞋子也做不出来。所以流水线是系统可调度执行的基本单位。
  • 工厂包含多条流水线,即进程包含多个线程,而多条流水线上的工人又共享工厂里的食堂、厕所、宿舍,线程之间共享所在进程的资源。

二、线程三种实现

1、继承Thread类

public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//3、创实例,并调用start()方法开启线程。new MyThread().start();new MyThread().start();}//1、定义一个类MyThread继承Thread,并重写run方法class MyThread extends Thread {@Overridepublic void run() {//2、将执行的代码写在run方法中。Log.d(TAG, "线程名字:" + Thread.currentThread().getName());}}
}

2、实现Runnable接口

public class MainActivity extends AppCompatActivity {public static final String TAG = MainActivity.class.getSimpleName();@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//3、创建Thread对象, 传入MyRunnable的实例,并调用start()方法开启线程。Thread thread = new Thread(new MyRunnable());thread.start();Thread thread1 = new Thread(new MyRunnable());thread1.start();}// 1、定义一个类MyRunnable实现Runnable接口,并重写run方法。class MyRunnable implements Runnable {public void run() {//2、将执行的代码写在run方法中。Log.d(TAG, "线程名字:" + Thread.currentThread().getName());}}
}

3 、通过Callable和Future创建有返回值的多线程

public class MainActivity extends AppCompatActivity {private final String TAG = this.getClass().getSimpleName();@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//3、创建线程池对象,调用submit()方法执行MyCallable任务,并返回Future对象ExecutorService pool = Executors.newSingleThreadExecutor();Future<Integer> f1 = pool.submit(new MyCallable());//4、调用Future对象的get()方法获取call()方法执行完后的值try {Log.d(TAG, "sum = " + f1.get());} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}//5、关闭线程池pool.shutdown();}//1、自定义一个类MyCallable实现Callable接口,并重写call()方法public class MyCallable implements Callable<Integer> {@Overridepublic Integer call() throws Exception {//2、将要执行的代码写在call()方法中int sum = 0;for (int i = 0; i <= 100; i++) {sum += i;}return sum;}}
}

三、线程的生命周期

1、线程的生命周期包括:新建New,就绪Runnable,运行Running,阻塞Blocked,和死亡Dead,5种状态。

新建:程序使用new关键字之后,该线程就处于新建状态,jvm为其分配内存,并初始化成员变量。

就绪:程序调用start() 方法之后,该线程就处于就绪状态,jvm为其创建方法调用栈和PC计数器。

运行:如果就绪状态的线程获得了CPU,那么程序就处于运行状态。

阻塞:指一个线程在执行过程中暂停,以等待某个条件的触发。

死亡:线程执行体执行结束,以及抛出一个未捕获的ExceptionError,或者直接调用stop()方法结束该线程。可以通过线程对象的isAlive()方法,来判断线程对象的状态。

2、生命周期转换

(1)运行到阻塞:

  • 线程调用sleep()方法,主动放弃所占有的CPU资源;
  • 线程调用了一个阻塞式IO方法,在该方法返回之前,该线程被阻塞;
  • 线程试图获得一个同步监视器,但是该同步监视器被其他线程所持有;
  • 线程等待某个通知notify()notify()通常与wait()配合使用;
  • 线程调用suspend(),挂起,该方法容易造成死锁,不建议使用。

(2)阻塞到就绪:

  • sleep()方法的线程经过了指定的sleep的时间;
  • 阻塞式IO方法返回值;
  • 成功获得了同步监视器;
  • 线程获得了其他线程发出的通知,被唤醒;
  • 挂起的线程调用了resume()方法恢复。

(3)状态转换图
线程生命周期.png

四、线程常用方法

1、setPriority(int newPriority) - 设置线程优先级

  • 设置线程的优先级来改变线程争抢到时间片的概率,优先级高的争抢到时间片的概率越大;
  • 优先级的取值范围:1~10,默认为5,数字越大,优先级越高;
  • 这个方法的调用必须在start之前,否则没有任何意义;
  • 使用方法getPriority(),获取当前线程优先级。

2、setDeamon(boolean b) - 设置后台线程

  • 如果所有的前台线程死亡,那么后台线程会自动死亡;
  • 默认情况下所有的线程都是前台线程;
  • 这个方法的调用必须在start之前。

3、sleep(long millis) - 设置线程休眠

  • 让当前线程暂停millis毫秒,并进入阻塞状态,睡眠状态的线程不会释放同步监视器,在此期间该线程不会获得执行的机会;
  • 使用sleep方法时需要捕捉InterruptedException或者抛出该异常。

4、interrupt() - 线程中断

  • 表示的并不是将线程结束,而是表示清除阻塞状态;
  • 中断线程操作实质上是修改了一下中断标示位为true
  • 如果线程处于阻塞状态,抛出异常InterruptedException
public class MainActivity extends AppCompatActivity {public static final String TAG = MainActivity.class.getSimpleName();@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Thread thread = new Thread(new MyRunnable());thread.start();try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}//打断休眠线程thread.interrupt();}class MyRunnable implements Runnable {public void run() {try {Log.i(TAG, "----开始休眠-----");Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();Log.i(TAG, "----线程中断-----");}Log.i(TAG, "----休眠后执行-----");}}
}

执行结果:报异常,提示中断,取消线程阻塞,执行休眠后操作。interrupt.PNG

public class MainActivity extends AppCompatActivity {public static final String TAG = MainActivity.class.getSimpleName();@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Thread thread = new Thread(new MyRunnable());thread.start();thread.interrupt();}class MyRunnable implements Runnable {public void run() {for (int i = 0; i < 5; i ++){Log.i(TAG,"打印: " + i);if (Thread.interrupted()){Log.i(TAG, "----线程被中断了-----");}}Log.i(TAG, "----执行完了- interrupt state: " + Thread.interrupted());}}
}

执行结果:interrupted()只有主线程调用的时候才会是truefor循环结束后再次执行是falseinterrupt2.PNG

5、join() - 线程合并

  • 在执行原来的线程的过程中,如果遇到了合并线程,则优先执行合并进来的线程,当合并线程执行完毕之后,再接着执行原来的线程;
  • 调用join方法之前,一定要将线程start
  • join(0)的意思不是A线程等待B线程0秒,而是A线程等待B线程无限时间,直到B线程执行完毕,即join(0)等价于join()
public class MainActivity extends AppCompatActivity {public static final String TAG = MainActivity.class.getSimpleName();@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Thread thread1 = new Thread(new JoinRunnable());thread1.start();for (int i = 0; i < 5; i++) {//主线程执行1的时候,把执行权让给了子线程if (i == 1) {try {thread1.join();} catch (InterruptedException e) {e.printStackTrace();}}Log.i(TAG, Thread.currentThread().getName() + "正在运行....");}}class JoinRunnable implements Runnable {@Overridepublic void run() {for (int i = 0; i < 3; i++) {try {Thread.sleep(1000);Log.i(TAG, Thread.currentThread().getName() + "正在运行....");} catch (InterruptedException e) {e.printStackTrace();}}}}
}

执行结果:
join3.PNG
6、yield() - 线程让步

  • 使得正在执行的线程暂停,但不会阻塞线程,释放自己拥有的CPU,线程进入就绪状态。
  • 只有优先级与当前线程相同,或者优先级比当前线程更高的线程才有可能获得执行机会,但是可能是当前线程又进入到“运行状态”继续运行。
public class MainActivity extends AppCompatActivity {public static final String TAG = "test";@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Thread thread1 = new Thread(new MyRunnable());thread1.start();}class MyRunnable implements Runnable {@Overridepublic void run() {long begainTime = System.currentTimeMillis();int count = 0;for (int i = 0; i < 5000000; i++) {//结果2需要将下面注释放开//Thread.yield();count = count + (i + 1);}long endTime = System.currentTimeMillis();Log.i(TAG, "用时:" + (endTime - begainTime) + "ms");}}
}

运行结果1:
yield1.PNG

运行结果2,执行时放开Thread.yield()
yield3.PNG

  • yield()也不会释放锁标志,示例如下:
public class MainActivity extends AppCompatActivity {public static final String TAG = "test";@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Thread thread1 = new Thread(new MyRunnable());Thread thread2 = new Thread(new MyRunnable());thread1.start();thread2.start();}static class MyRunnable implements Runnable {private static Object obj = new Object();@Overridepublic void run() {synchronized (obj) {for(int i = 0;i < 5;i++) {Log.i(TAG, Thread.currentThread().getName() + "正在执行i: " + i);if(i == 2) {Thread.currentThread().yield();}}}}}
}

运行结果,Thread-2获取锁以后,就算yield,也没释放锁:
yield4.PNG
7、stop() - 线程停止

  • 官方不建议使用该方法,因为stop不安全,stop会解除由线程获取的所有锁定,当在一个线程对象上调用stop()方法时,这个线程对象所运行的线程就会立即停止,假如一个线程正在执行:synchronized void { x = 3; y = 4;} 由于方法是同步的,多个线程访问时总能保证x,y被同时赋值,而如果一个线程正在执行到x = 3;时,被调用了stop()方法,即使在同步块中,它也会马上stop了,这样就产生了不完整的脏数据。

参考文章:
对进程、线程、多线程、线程池的理解
带你通俗易懂的理解——线程、多线程与线程池
线程类的常见方法介绍
java多线程以及Android多线程

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

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

相关文章

10.8c++作业

#include <iostream>using namespace std; class Rect {int width; //宽int height; //高 public://初始化函数void init(int w,int h){widthw;heighth;}//更改宽度void set_w(int w){widthw;}//更改高度void set_h(int h){heighth;}//输出矩形周长和面积void show(){co…

ASO优化之应用程序图标的设计技巧

用户在App Store页面上&#xff0c;首先看到的是我们的移动应用程序图标&#xff0c;所以应用图标的设计至关重要。如果这不能引起用户的注意&#xff0c;他们可能不会费心去了解有关我们的应用的更多信息。 1、脱颖而出的重要性。 具有附加价值&#xff0c;如果做得好&#x…

bigemap在林业勘测规划设计行业的一些应用

选择Bigemap的原因&#xff1a; 主要注重影像的时效性&#xff0c;软件的影像时效性比其他的更新快&#xff0c;更清晰。 使用场景&#xff1a; 1.林业督查&#xff0c;主要是根据国家下发的图斑&#xff0c;结合测绘局的影像以及bigemap的较新影像对比去年和今年的林地变化。…

MySQL——使用mysqldump备份与恢复数据

目录 1.mysqldump简介 2.mysqldump备份数据 2.1 备份所有数据库 2.2 备份一个/多个数据库 2.3 备份指定库中的指定表 3.mysqldump恢复数据 3.1 恢复数据库 3.2 恢复数据表 1.mysqldump简介 mysqldump命令可以将数据库中指定或所有的库、表导出为SQL脚本。表的结构和表中…

Survey on Cooperative Perception in an Automotive Context 论文阅读

论文链接 Survey on Cooperative Perception in an Automotive Context 0. Abstract 本文就协同基础设施领域提供相关环境的调查回顾了感知中涉及的主要模块&#xff1a;定位&#xff0c;目标检测和跟踪&#xff0c;地图生成提供了协同感知的 SWOT 1. Intro 无人驾驶汽车的背…

力扣 -- 647. 回文子串

解题步骤&#xff1a; 参考代码&#xff1a; class Solution { public:int countSubstrings(string s) {int ns.size();vector<vector<bool>> dp(n,vector<bool>(n));//无需初始化int ret0;//一定要从下往上填写每一行for(int in-1;i>0;i--){//每一行的i…

Acwing.889 满足条件的01序列

题目 给定n个0和n个1&#xff0c;它们将按照某种顺序排成长度为2n的序列&#xff0c;求它们能排列成的所有序列中&#xff0c;能够满足任意前缀序列中0的个数都不少于1的个数的序列有多少个。 输出的答案对109&#xff0b;7取模。 输入格式 共一行&#xff0c;包含整数n。 …

嵌入式Linux裸机开发(一)基础介绍及汇编LED驱动

系列文章目录 文章目录 系列文章目录前言IMX6ULL介绍主要资料IO表现形式 汇编LED驱动原理图初始化流程时钟设置IO复用设置电气属性设置使用GPIO 编写驱动编译程序编译.o文件地址链接.elf格式转换.bin反汇编&#xff08;其他&#xff09; 综合成Makefile完成一步编译烧录程序imx…

经典循环神经网络(一)RNN及其在歌词数据集上的应用

经典循环神经网络(一)RNN及其在歌词数据集上的应用 1 RNN概述 在深度学习兴起之前&#xff0c;NLP领域一直是统计模型的天下&#xff0c;例如词对齐算法GIZA&#xff0c;统计机器翻译开源框架MOSES等等。在语言模型方向&#xff0c;n-gram是当时最为流行的语言模型方法。n-gr…

计算机竞赛 题目:基于卷积神经网络的手写字符识别 - 深度学习

文章目录 0 前言1 简介2 LeNet-5 模型的介绍2.1 结构解析2.2 C1层2.3 S2层S2层和C3层连接 2.4 F6与C5层 3 写数字识别算法模型的构建3.1 输入层设计3.2 激活函数的选取3.3 卷积层设计3.4 降采样层3.5 输出层设计 4 网络模型的总体结构5 部分实现代码6 在线手写识别7 最后 0 前言…

【uniapp】小程序开发6:自定义状态栏

一、自定义状态栏 可以设置某个页面的状态栏自定义或者全局状态栏自定义。 这里以首页状态栏为例。 1&#xff09;pages.json 中配置"navigationStyle": "custom"&#xff0c;代码如下&#xff1a; {"pages": [ {"path": "pa…

Bridge Champ助力我国桥牌阔步亚运, Web3游戏为传统项目注入创新活力

本届杭州亚运会,中国桥牌队表现杰出,共斩获1金1银1铜佳绩,其中女子团体夺得冠军,混合团体获得亚军。这充分展现了我国桥牌的实力,也彰显了桥牌作为亚运会体育竞技项目的影响力。与此同时,Web3游戏Bridge Champ为传统桥牌项目带来创新模式,将有望推动桥牌运动在亚运舞台上焕发新…

SpringMVC的请求映射:路由请求的精准导航

SpringMVC的请求映射&#xff1a;路由请求的精准导航 SpringMVC是一个用于构建Web应用程序的强大框架&#xff0c;它提供了众多的特性和组件来简化开发过程。其中&#xff0c;请求映射是SpringMVC中的一个关键特性&#xff0c;用于将HTTP请求映射到具体的处理方法。本文将深入…

【Python】基于OpenCV人脸追踪、手势识别控制的求生之路FPS游戏操作

【Python】基于OpenCV人脸追踪、手势识别控制的求生之路FPS游戏操作 文章目录 手势识别人脸追踪键盘控制整体代码附录&#xff1a;列表的赋值类型和py打包列表赋值BUG复现代码改进优化总结 py打包 视频&#xff1a; 基于OpenCV人脸追踪、手势识别控制的求实之路FPS游戏操作 手…

Mysql 分布式序列算法

接上文 Mysql分库分表 1.分布式序列简介 在分布式系统下&#xff0c;怎么保证ID的生成满足以上需求&#xff1f; ShardingJDBC支持以上两种算法自动生成ID。这里&#xff0c;使用ShardingJDBC让主键ID以雪花算法进行生成&#xff0c;首先配置数据库&#xff0c;因为默认的注…

BootstrapBlazor企业级组件库:前端开发的革新之路

作为一名Web开发人员&#xff0c;开发前端我们一般都是使用JavaScript&#xff0c;而Blazor就是微软推出的基于.Net平台交互式客户Web UI 框架&#xff0c;可以使用C#替代JavaScript&#xff0c;减少我们的技术栈、降低学习前端的成本。 而采用Blazor开发&#xff0c;少不了需…

React核心原理与实际开发

学习目标 React是啥&#xff1f; 官方定义&#xff1a;将前端请求获取到的数据渲染为HTML视图的JavaScript库。 一、React入门 1、React项目创建 直接创建react&#xff0c;使用初始化会创建package.json npm init -y再安装 2、React基本使用 使用纯JS创建ReactDOM&#…

Flink学习笔记(二):Flink内存模型

文章目录 1、配置总内存2、JobManager 内存模型3、TaskManager 内存模型4、图形化展示5、实际案例计算内存分配 1、配置总内存 Flink JVM 进程的进程总内存&#xff08;Total Process Memory&#xff09;包含了由 Flink 应用使用的内存&#xff08;Flink 总内存&#xff09;以…

iTunes更新iOS17出现发生未知错误4000的原因和解决方案

有不少人使用iTunes更新iOS 17时出现「无法更新iPhone发生未知的错误4000」的错误提示&#xff0c;不仅不知道iTunes升级失败的原因&#xff0c;也无从解决iPhone无法更新4000的问题。 小编今天就分享iPhone更新iOS系统出现4000错误提示的原因和对应的解决方案。 为什么iPhone…

MySQL Cluster 简介

文章目录 1.简介2.组成参考文献 1.简介 MySQL Cluster 是官方推出的基于 NDB&#xff08;Network DataBase&#xff09;存储引擎的高可用和可伸缩的分布式数据库系统。 以下是 MySQL NDB Cluster 的主要特点和能力&#xff1a; 高可用&#xff1a;MySQL Cluster 具有内置的高…