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,那么程序就处于运行状态。
阻塞:指一个线程在执行过程中暂停,以等待某个条件的触发。
死亡:线程执行体执行结束,以及抛出一个未捕获的Exception
或Error
,或者直接调用stop()
方法结束该线程。可以通过线程对象的isAlive()
方法,来判断线程对象的状态。
2、生命周期转换
(1)运行到阻塞:
- 线程调用
sleep()
方法,主动放弃所占有的CPU资源; - 线程调用了一个阻塞式IO方法,在该方法返回之前,该线程被阻塞;
- 线程试图获得一个同步监视器,但是该同步监视器被其他线程所持有;
- 线程等待某个通知
notify()
,notify()
通常与wait()
配合使用; - 线程调用
suspend()
,挂起,该方法容易造成死锁,不建议使用。
(2)阻塞到就绪:
sleep()
方法的线程经过了指定的sleep
的时间;- 阻塞式IO方法返回值;
- 成功获得了同步监视器;
- 线程获得了其他线程发出的通知,被唤醒;
- 挂起的线程调用了
resume()
方法恢复。
(3)状态转换图
四、线程常用方法
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, "----休眠后执行-----");}}
}
执行结果:报异常,提示中断,取消线程阻塞,执行休眠后操作。
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()
只有主线程调用的时候才会是true
。for
循环结束后再次执行是false
。
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();}}}}
}
执行结果:
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:
运行结果2,执行时放开Thread.yield()
:
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
,也没释放锁:
7、stop() - 线程停止
- 官方不建议使用该方法,因为
stop
不安全,stop
会解除由线程获取的所有锁定,当在一个线程对象上调用stop()
方法时,这个线程对象所运行的线程就会立即停止,假如一个线程正在执行:synchronized void { x = 3; y = 4;}
由于方法是同步的,多个线程访问时总能保证x,y
被同时赋值,而如果一个线程正在执行到x = 3
;时,被调用了stop()
方法,即使在同步块中,它也会马上stop
了,这样就产生了不完整的脏数据。
参考文章:
对进程、线程、多线程、线程池的理解
带你通俗易懂的理解——线程、多线程与线程池
线程类的常见方法介绍
java多线程以及Android多线程
相关文章:

Android多线程学习:线程
一、概念 进程:系统资源分配的基本单位,进程之间相互独立,不能直接访问其他进程的地址空间。 线程:CPU调度的基本单位,线程之间共享所在进程的资源,包括共享内存,公有数据,全局变量…...

canvas 入门
canvas 入门 canvas是干什么的?canvas 绘制直线canvas画虚线canvas 绘制三角形canvas 绘制正方形canvas 绘制圆形、圆弧与椭圆canvas绘制文本canvas绘制图片 canvas是干什么的? <canvas> 是HTML5中的标签,它是一个容器,可以…...

建议收藏!混迹职场多年总结出的8大技巧!
1. 不要吃“哑巴”亏:不管在什么企业,一定要“会说话”,敢于表达自己,但是又兼顾身边人的感受,考虑好自己的言行将会带来的后果。良好的沟通技巧对于在职场中建立良好的人际关系和解决问题至关重要。学会倾听、表达和理…...

OpenCV4(C++)—— 视频和摄像头的加载、显示与保存
文章目录 一、加载与显示二、保存 一、加载与显示 视频或摄像头的加载是使用 cv::VideoCapture 类。(这个类和 ifstream 类比较相似,视频或摄像头的加载和文本文件操作是大致相同。主要步骤:(1)加载(打开&a…...

excel功能区(ribbonx)编程笔记6-box的使用
box元素用来在组里指定的控件周围放置一个可视的框,其主要目的是将控件作为一个单元组合在一起。 通常情况下,分配到组中的每个控件都被放置在先前的控件下面直到该列被填满,然后下一个控件被放置在其右侧列的顶行。然而,通过在框里面组合命令,可以将几个控件视作一个整体…...

oralce配置访问白名单的方法
目录 配置sqlnet.ora文件 重新加载使配置生效 注意事项 Oracle数据库安全性提升:IP白名单的配置方法 随着互联网的发展,数据库安全问题也越来越严重。Oracle是目前使用较为广泛的一款数据库管理系统,而IP白名单作为提升数据库安全性的有效…...

ToBeWritten之让响应团队参与并做好沟通
也许每个人出生的时候都以为这世界都是为他一个人而存在的,当他发现自己错的时候,他便开始长大 少走了弯路,也就错过了风景,无论如何,感谢经历 转移发布平台通知:将不再在CSDN博客发布新文章,敬…...

ffmpeg ts 关于av_seek_frame
1 ffmpeg命令行 一般对视频文件的裁剪 我们通过一行 ffmpeg命令行即可实现,比如 ffmpeg -ss 0.5 - t 3 - i a.mp4 vcodec copy b.mp4 其中 -ss 放置较前 开启精准seek定位 对于mp4而言 seek将从moov中相关索引表查找 0.5s时刻附近最近的关键帧 (此描述…...

【C++】set map 的底层封装
在了解底层封装之前除了对set和map的使用情况要有一定了解,还需要先学习一下二叉搜索树,AVL树,红黑树这些数据结构。 【C】二叉搜索树 【C】AVL树 & 红黑树 RBTree.h enum Colour {RED,BLACK };template<class T> class RBTreeNo…...

JavaWeb整体介绍
JavaWeb整体介绍 什么是Java Web Web:全球广域网,也称为万维网(www),能够通过浏览器访问的网站JavaWeb:是使用Java技术解决相关web互联网领域的技术栈(就是用java开发网站) 网页&a…...

一些常见分布-正态分布、对数正态分布、伽马分布、卡方分布、t分布、F分布等
目录 正态分布 对数正态分布 伽马分布 伽马函数 贝塔函数 伽马分布 卡方分布 F分布 t分布 附录 参考文献 本文主要介绍一些常见的分布,包括正态分布、对数正态分布、伽马分布、卡方分布、F分布、t分布。给出了分布的定义,推导了概率密度函数&…...

科技云报道:押注向量数据库,为时过早?
科技云报道原创。 在大模型的高调火热之下,向量数据库也获得了前所未有的关注。 近两个月内,向量数据库迎来融资潮,Qdrant、Chroma、Weaviate先后获得融资,Pinecone宣布1亿美元B轮融资,估值达到7.5亿美元。 东北证券…...

铭控传感亮相2023国际物联网展,聚焦“多场景物联感知方案”应用
金秋九月,聚焦IoT基石技术,荟萃最全物联感知企业,齐聚IOTE 2023第20届国际物联网展深圳站。铭控传感携智慧楼宇,数字工厂,智慧消防,智慧泵房等多场景物联感知方案及多品类无线传感器闪亮登场,现…...

前端demo: 实现对图片进行上传前的压缩功能
前端可以使用canvas和File API来对图片进行压缩和缩放处理,以下是一个示例代码 : 压缩方法compressImg这段代码是实现对图片进行上传前的压缩功能 1. 定义了一个压缩图片的函数 compressImg,接受两个参数:file表示要压缩的文件,q…...

计算机网络(文章链接汇总)
参考引用 计算机网络微课堂-湖科大教书匠计算机网络(第7版)-谢希仁 计算机网络(一):概述计算机网络(二):物理层计算机网络(三):数据链路层计算机网…...

黑科技-Android
1热更新(热修复):apk不用发版,就能修复bug 原理:我们修复好了bug的时候,把那些有改动的java源码编译成class,再打包成dex,然后通过反射技术放到dexElements数组的最前面,…...

450. 删除二叉搜索树中的节点
给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。 一般来说,删除节点可分为两个步骤: 首先…...

python安全工具开发基础
文章目录 拷贝、with、is深拷贝、浅拷贝with 三器一闭迭代器生成器闭包装饰器 动态绑定垃圾回收网络编程UdpTcp 协程mysql预处理防止注入 redis未授权/弱密码 拷贝、with 、is a [11, 22, 33] b [11, 22, 33] ca print(id(a)) print(id(b)) print(id(c))print(a b) print(…...

26 docker前后端部署
[参考博客]((257条消息) DockerNginx部署前后端分离项目(SpringBootVue)的详细教程_在docker中安装nginx实现前后端分离_这里是杨杨吖的博客-CSDN博客) (DockerNginx部署前后端分离项目(SpringBootVue)) 安装docker # 1、yum 包更新到最新 yum update # 2、安装需要的软件包…...

[linux] SFTP文件传输基本命令 --- xshell 直接上传文件
2.sftp - 上传文件:如果上传/下载的是文件夹, 在put/get命令后加上-r参数即可。 上传文件: 把本地服务器的/www/wwwroot目录下面的study.log文件上传到远程服务器的/www/server目录下。 sftp> lcd /www/wwwroot sftp> put study.log /www/server…...

Tomcat 多实例
一、Tomcat 多实例 1、概念: Tomcat 多实例是指在同一台服务器上运行多个独立的 Tomcat 服务器实例。它们可以同时运行在同一台物理服务器或虚拟服务器上,但它们彼此之间是相互独立的,有各自的配置、应用程序和资源。 2、配置:…...

全民拼购模式:电商的新趋势和机遇
全民拼购模式是一种基于社交电商的新型模式,它通过拼团、拼购等方式,让消费者享受更优惠的价格和更便捷的购物体验。这种模式的出现,不仅为电商平台注入了新的活力,也成为了消费者追求高性价比商品的新选择。 全民拼购模式有以下…...

免费使用,媲美Midjourney!微软在Bing Chat等提供—DALL-E 3
微软在官网宣布,将OpenAI最新模型DALL-E 3集成在Bing Chat和Bing Image Create中,并免费提供给用户使用。 据悉,DALL-E 3是一款类Midjourney产品,通过文本就能生成二次元、3D、朋克、涂鸦、素描、黑白、极简、印象派、位面像素等…...

Nacos中AP和CP 切换
CAP理论 这个定理的内容是指的是在一个分布式系统中、Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可得兼。 一致性(C):在分布式系统中&a…...

服务器中勒索病毒怎么解决?勒索病毒解密,数据恢复
服务器中勒索病毒是一件低频、高概率的事情。而且一旦用户的服务器中招以后,想要处理无论是经济成本还是时间成本都非常的高。也会对企业的生产经营造成很大的影响。所以绝大多数企业主都很关心服务器中勒索病毒后怎么解决。针对这个问题,云天数据恢复中…...

全面解析UDP协议(特点、报文格式、UDP和TCP的区别)
了解UDP(User Datagram Protocol) UDP是无连接通信协议,即在数据传输时,数据的发送端和接收端不建立逻辑连接。简单来说,当一台计算机向另外一台计算机发送数据时,发送端不会确认接收端是否存在࿰…...

iPhone15手机拓展坞方案,支持手机快充+传输数据功能
手机拓展坞的组合有何意义?首先是数据存储场景,借助拓展坞扩展出的接口,可以连接U盘、移动硬盘等采用USB接口的设备,实现大文件的快速存储或者流转;其次是图片、视频的读取场景,想要读取相机、无人机SD/TF存…...

优化理论笔记
目录 一、前言 二、优化问题的基本要素 三、优化问题分类 四、最优值类型 五、最优化方法分类 六、非约束优化 1、问题定义 2、优化算法 1)一般局部搜索过程 2)集束搜索 3)禁忌搜索 4)模拟退火 5)蛙跳算法…...

FastAPI学习-23.异常处理器 exception_handler
前言 通常我们可以通过 raise 抛出一个 HTTPException 异常,请求参数不合法会抛出RequestValidationError 异常,这是最常见的2种异常。 HTTPException 异常 向客户端返回 HTTP 错误响应,可以使用 raise 触发 HTTPException。 from fastap…...

国庆出游远程实测:ToDesk 、TeamViewer、AnyDesk远程控制软件稳定性
ToDesk 、TeamViewer、AnyDesk远程控制软件稳定性 【前言】【实测软件】【测试环境】【实操体验】1. 软件安装2. 登录速度3. 文件传输4. 操作延迟5. 画面清晰度6. 安全防护 【本文小结】 【前言】 随着科技的不断发展,远程控制软件已成为我们生活中不可或缺的一部分…...