Android并发编程与多线程

   一、Android线程基础

1.线程和进程

  • 一个进程最少一个线程,进程可以包含多个线程
  • 进程在执行过程中拥有独立的内存空间,而线程运行在进程内

2.线程的创建方式

  • new Thread:

        缺点:缺乏统一管理,可能无限制创建线程,相互之间竞争,可能占用过多的系统资源导致死机或OOM

    new Thread(new Runnable() {@Overridepublic void run() {}}).start();class MyThread extends Thread{@Overridepublic void run() {super.run();}}new MyThread().start();
  • AysncTask:轻量级异步任务工具类,提供任务执行的进度回调给UI线程

        使用场景:需要知道任务执行的进度,多个任务串行执行

        缺点:生命周期和宿主的生命周期不同步,可能发生内存泄漏,默认情况下任务串行执行

        作为用来替代Thread + Handler的辅助类,AsyncTask可以很轻松地执行异步任务并更新ui,但由于context泄露,回调遗漏,configuration变化导致崩溃,平台差异性等原因,在api 30(Android 11)中AsyncTask被正式废弃:

        使用execute方法,串行执行,即先来后到,如果其中有一条任务休眠,或者执行时间过长,后面的任务都将被阻塞

        使用内置THREAD_POOL_EXECUTOR线程池,并发执行

  • HandlerThread:适用于主线程需要和工作线程通信,或者持续性任务,比如轮询,所有任务串行执行

        缺点:不会像普通线程一样主动销毁资源,会一直运行,可能造成内存泄漏(可以定义成静态,防止内存泄漏)

  • IntentService:适用于任务需要跨界面读取任务执行的进、结果。比如:后台上传图片、批量操作数据库等。任务完成后,会自我结束,不需要手动stopService
  • ThreadPoolExecutor:适用快读出来大量耗时较短的任务场景
    • Executors.newCacheThreadPool();//线程可复用线程池
    • Executors.newFixedThreadPool();//固定线程数量线程池
    • Executors.newScheduleThreadPool();//可指定定时任务线程池
    • Executors.newSingleExecutor();//线程数量为1的线程池

3.线程的优先级

  • 线程的优先级具有继承性
  • 设置优先级的方法
    • java api:java.lang.Thread.setPriority(int newPriority);优先级必须为[1~10],优先级的值越高,获取CPU时间片的概率越高,UI线程的优先级为5  效果不是很明显
    • Android api:android.os.Process.setThreadPriority(int newPriority);优先级可设置[-20~19],优先级的值越低,获取时间片的概率越高,UI线程的优先级为-10 效果明显

4.线程的状态

  • NEW:初始状态,线程被新建,还没有调用start方法
  • RUNNABLE:运行状态,包括运行中和就绪
  • BLOCKED:阻塞状态,表示线程阻塞于锁
  • WAITING:等待状态,需要其他线程通知唤醒
  • TIME_WAITING:超时等待状态,表示可以在指定的时间超过后自行返回
  • TERMINATED:终止状态,表示当前线程已经执行完毕

关键方法:

  • wait:等待线程池,释放资源对象锁,可使用notify,notifyAll,或等待超时时间来唤醒
  • join:等待目标线程执行完后再执行此线程
  • yield:暂停当前正在执行的线程对象,不会释放当前线程持有的任何锁资源,使用优先级或更高优先级的线程有执行的机会,这个方法机会用不到
  • sleep:使调用线程进入休眠状态,一般情况下会释放线程锁对象,但如果在一个synchronized块中执行sleep,线程虽会休眠,但不会释放资源对象锁

5.线程间消息通讯

主线程向子线程发送消息

二、多线程开发核心知识点

1.线程并发安全

本质:能够让并发线程有序的运行(可能是先来后到排队,也可能被插队,同一时刻只能一个线程有权访问同步资源),线程执行的结果,能够对其它线程可见

2.线程安全的分类

  • 根据线程要不要锁住同步资源
    • 锁住:悲观锁  synchronized ReentrantLock
    • 不锁住:乐观锁  AtomicInteger  AtomicBoolean
  • 锁住同步资源失败要不要阻塞?
    • 阻塞:阻塞锁  synchronized ReentrantLock
    • 不阻塞:自旋锁  AtomicInteger  AtomicBoolean 
  • 获取资源锁时,要不要插队
    • 插队:公平锁  ReentrantLock
    • 不插队:非公平锁 synchronized ReentrantLock
  • 一个线程中的多个流程能不能获取同一把锁
    • 可重入锁: synchronized ReentrantLock
    • 不可重入锁
  • 多线程共享一把锁
    • 能:共享锁 RendLock
    • 不能:排他锁 WriteLock
  • 多线程竞争同步资源 synchronized
    • 不锁住资源,多个线程中只有一个能修改成功,其他会重试  无锁
    • 同一线程执行同步资源时自动获取锁   偏向锁
    • 多个线程竞争资源时,没有获取到资源的线程自选等待  轻量级锁
    • 多个线程竞争资源时,没有获取到资源的线程被阻塞等待唤醒  重量级锁

3.如何线程安全

AtomicInterger 原子包装类

  • CAS实现无锁数据更新,自旋的设计能够有效避免线程因阻塞-唤醒带来的系统资源开销
  • 适用场景:多线程计数,原子操作,并发数量小
  • 使用案例
        AtomicInteger atomicInteger = new AtomicInteger(1);atomicInteger.getAndIncrement();atomicInteger.getAndAdd(2);atomicInteger.getAndDecrement();atomicInteger.getAndAdd(-2);

volatile 可见性修饰

  • volatile修饰的成员变量在每次被线程访问时,都强迫从共享内存重新读取该成员的值,而且,当成员变量值发生变化时,强迫将变化的值重新写入共享内存
  • 缺点:不能保证原子性,不能解决非原子操作的线程安全性,性能不及原子类高
  • 使用案例
    volatile int count = 0;public void test() {// 赋值操作是原子性操作,对其他线程可见count = 1;//非原子操作,其他线程不可见count = count + 1;count++;}

synchronized

  • 锁方法。加在方法上,未获取到对象锁的其他线程都不可以访问该对象
  • 锁Class对象。加在static方法上相当于给Class对象加锁,哪怕是不同的Java对象实例,也需要排队执行
  • 锁代码块。未获取到对象锁的其他线程可以执行同步代码块之外的代码

优势:哪怕一个同步方法中出现了异常,那么JVM也能够为我们自动释放锁,能主动从而规避死锁,不需要开发者主动释放锁

劣势:

  • 必须要等到获取锁对象的线程执行完成,或出现异常,才能释放掉,不能中途释放锁,不能中断一个正在试图获取锁的线程
  • 多线程竞争的时候,不知道获取锁成功与否,不够灵活
  • 每个锁仅有单一的条件不能设定超时

ReentrantLock

悲观锁,可重入锁,公平锁,非公平锁

  • 基础用法:
        ReentrantLock lock = new ReentrantLock();try {lock.lock();//……} finally {lock.unlock();}//获取锁,获取不到会阻塞lock.lock();//尝试获取锁,成功返回truelock.tryLock();//在一定的时间内去不断尝试获取锁lock.tryLock(3000, TimeUnit.MICROSECONDS);//可使用Thread.interrupt()打断阻塞,退出竞争,让给其他线程lock.lockInterruptibly();
  • 可重入,避免死锁
    ReentrantLock lock = new ReentrantLock();public void doWork() {try {lock.lock();doWork();//递归调用,使得统一线程多次获得锁} finally {lock.unlock();}}
  • 公平锁:所有进入阻塞的线程排队依次均有机会执行

使用场景:交易

//传入true 就是公平锁,传入false 或者不传就是非公平锁 
ReentrantLock lock = new ReentrantLock(true);
  • 非公平锁:默认,允许线程插队,避免每一个线程都进入阻塞,在唤醒带来的性能开销。性能高,因为线程可以插队,但是会导致队列中可能存在线程饿死的情况,一直得不到锁,一直得不到执行

使用场景:synchronized,很多场景都是非公平锁

  • 进阶用法 -- Condition条件对象
  Condition worker = lock.newCondition();//进入阻塞,等待唤醒worker.await();//唤醒指定线程worker1.signal();

共享锁,排他锁

  • 共享锁:所有线程都可以同时获得,并发量高。如:读操作
  • 排他锁:同一时刻只能一个线程有权修改资源。如:写操作
ReentrantReadWriteLock.ReadLock
ReentrantReadWriteLock.WriteLock

三、正确使用锁和原子类

1.减少持锁时间

尽管锁在同一时间只能允许一个线程持有,其他想要占用锁的线程都得在临界区外等待锁的释放,这个等待的时间要尽可能的短

2.锁分离

读写锁分离,写锁才需要同步处理。对于大多数应用来说,读的场景更多一些,读写锁分离,可以提高系统性能

3.锁粗化

多次加锁,释放锁合并成一次

对于一些不需要同步的代码,但能很快执行完毕,前后都有锁,这种情况可以进行锁粗化,整合成一次锁请求,释放。(锁请求、释放是需要性能开销的)

四、线程池

1.优势

  • 减低资源消耗。通过重复利用已创建的线程减低线程创建和销毁造成的消耗;
  • 提高响应速度。当任务到达时,任务可以不需要等待线程创建就能立即执行;
  • 提高线程的可管理性。线程是稀有资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。

2.Java中默认的线程池

线程池的默认构建

       ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 20, 5, TimeUnit.SECONDS,new PriorityBlockingQueue<>());executor.execute(() -> {});// 源码public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler) {}

参数

  • corePoolSize:线程池中的核心线程数量
  • maximumPoolSize:最大能创建的线程数量
  • keepAliveTime:非核心线程最大的存活时间
  • unit:keepAliveTime的时间单位
  • workQueue:等待队列,当任务提交时,如果线程中线程数量大于等于corePoolSize的时候,把任务放入等待队列
  • threadFactory:线程创建工厂,默认使用Executors.defaultThreadFactory()来创建线程,线程具有相同的NORM_PRIORITY优先级并且是非守护线程
  • handler:线程池的饱和就决策略。如果阻塞队列满了并且没有空闲的线程,这时如果继续提交任务,就需要采取一种策略处理该任务

JUC包下提供的集中线程池

        // 单一线程数,同时只有一个线程存活,但是线程等待队列无界Executors.newSingleThreadExecutor();// 线程可复用线程池,核心线程数为0,最大可创建的线程数为Interger.max,线程复用存活时间为60sExecutors.newCachedThreadPool();// 固定线程数量的线程池Executors.newFixedThreadPool(5);// 可执行定时任务,延迟任务的线程池Executors.newScheduledThreadPool(5);

线程池的重要方法

//提交任务,交给线程池调度
void execute(Runnable command) //关闭线程池,等待执行任务完成,不接受新的任务,但可以继续执行池子中已添加到等待队列的任务
void shutdown()//关闭线程池,不等待执行任务完成,不接受新的任务,也不再处理等待队列中的任务打断正在执行的任务
void shutdownNow()//返回线程池中所有任务的数据
long getTaskCount()//返回线程池中已执行完毕的任务数量
long getCompletedTaskCount() //返回线程池中已创建的线程数量
int getPoolSize()//返回当前正在运行的线程数量
int getActiveCount()

execute提交任务流程

addWorker的工作任务

  1. 检查线程池状态,能否继续创建线程
  2. 把runnable封装成worker,添加到工作队列
  3. 启动新建的线程
  4. runWorker方法中开启whille循环,执行本次任务,本次任务结束后,去检查等待队列中,是否有任务,拿来继续执行,达到复用目的

retry:双层for循环流程控制,使用retry可以退出外层循环

        int count = 0;retry:for (int i = 0; i < 10; i++) {for (int j = 0; j < 10; j++) {count++;if (count == 3) {break;}if (count == 4){break retry;}}}

五、协程

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

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

相关文章

卷积神经网络(CNN)mnist手写数字分类识别的实现

文章目录 前期工作1. 设置GPU&#xff08;如果使用的是CPU可以忽略这步&#xff09;我的环境&#xff1a; 2. 导入数据3.归一化4.可视化5.调整图片格式 二、构建CNN网络模型三、编译模型四、训练模型五、预测六、知识点详解1. MNIST手写数字数据集介绍2. 神经网络程序说明3. 网…

servlet页面以及控制台输出中文乱码

如图&#xff1a; servlet首页面&#xff1a; servlet映射页面&#xff1a; 以及控制台输出打印信息&#xff1a; 以上页面均出现中文乱码 下面依次解决&#xff1a; 1、首页面中文乱码 检查你的html或者jsp页面中meta字符集 如图设置成utf-8 然后重启一下tomcat 2、servl…

企业数字化过程中数据仓库与商业智能的目标

当前环境下&#xff0c;各领域企业通过数字化相关的一切技术&#xff0c;以数据为基础、以用户为核心&#xff0c;创建一种新的&#xff0c;或对现有商业模式进行重塑就是数字化转型。这种数字化转型给企业带来的效果就像是一次重构&#xff0c;会对企业的业务流程、思维文化、…

【数据结构与算法】JavaScript实现树结构(一)

文章目录 一、树结构简介1.1.简单了解树结构1.2.树结构的表示方式 二、二叉树2.1.二叉树简介2.2.特殊的二叉树2.3.二叉树的数据存储 三、二叉搜索树3.1.认识二叉搜索树3.2.二叉搜索树应用举例 一、树结构简介 1.1.简单了解树结构 什么是树&#xff1f; 真实的树&#xff1a;…

VS2017 IDE 编译时的 X86、x64位 是干什么的

指定编译出的程序是x86架构下的32位程序还是64位程序 VS2017项目配置X86改配置x64位_winform:把项目由x86改为x64-CSDN博客 vs平台选项&#xff1a;Any CPU,x86,x64_vs anycpu-CSDN博客

Jenkins中强制停止停不下来的job

# Script console 执行脚本 Jenkins 的提供了 script console 的功能&#xff0c;允许你写一些脚本&#xff0c;来调度 Jenkins 执行一些任务。 我们就可以利用 script console 来强制停止 job 执行。 首先进入 Jenkins 的 script console 页面&#xff1a; script console 路…

如何利用TSINGSEE青犀智能分析网关算法从人员、设备、行为三大角度进行监狱智能化升级改造

监狱作为关押犯人的重要场所&#xff0c;十分需要全天候全方位无死角的监控&#xff0c;但由于狱警人力有限&#xff0c;无法达到目前的监控需求。并且在监狱中&#xff0c;犯人众多也极易发生口角冲突&#xff0c;如若没有及时处理&#xff0c;就会发生难以挽回的意外。如何更…

MySQL分页查询的工作原理

前言 MySQL 的分页查询在我们的开发过程中还是很常见的&#xff0c;比如一些后台管理系统&#xff0c;我们一般会有查询订单列表页、商品列表页等。 示例&#xff1a; SELECT * FROM goods order by create_time limit 0,10; 在了解order by和limit的工作原理之前&#xff0c…

Python | 机器学习之逻辑回归

​&#x1f308;个人主页&#xff1a;Sarapines Programmer&#x1f525; 系列专栏&#xff1a;《人工智能奇遇记》&#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 目录结构 1. 机器学习之逻辑回归概念 1.1 机器学习 1.2 逻辑回归 2. 逻辑回归 2.1 实验目的…

开发一款小程序游戏需要多少钱?

小程序游戏的开发成本因多种因素而异&#xff0c;无法提供具体的固定数字。以下是影响小程序游戏开发成本的一些关键因素&#xff1a; 游戏规模和复杂度&#xff1a; 小程序游戏可以是简单的休闲游戏&#xff0c;也可以是更复杂的策略游戏。规模和复杂度会影响开发所需的时间和…

字节跳动小程序开发:探索创新的数字化世界

在数字化时代&#xff0c;字节跳动小程序开发成为企业数字化转型的关键一环。通过这一平台&#xff0c;企业能够借助先进的技术和丰富的功能&#xff0c;实现创新、引领市场潮流。本文将通过一些简单的技术代码示例&#xff0c;带你深入了解字节跳动小程序开发的魅力。 1. 小…

科研学习|研究方法——python T检验

一、单样本T检验 目的&#xff1a;检验单样本的均值是否和已知总体的均值相等前提条件&#xff1a; &#xff08;1&#xff09;总体方差未知&#xff0c;否则就可以利用 Z ZZ 检验&#xff08;也叫 U UU 检验&#xff0c;就是正态检验&#xff09;&#xff1b; &#xff08;2&a…

Android SmartTable根据int状态格式化文字及颜色

private void initData() {List<UserInfo> list new ArrayList<>();list.add(new UserInfo("一年级", "李同学", 6, 1, 120, 1100, 450, 0));list.add(new UserInfo("一年级", "张同学", 6, 2, 120, 1100, 450, 1));list…

工业数据采集分析 数据跨层次、跨环节、跨系统大整合

在“工业4.0”、“智能制造”、“工业互联网”的大背景下&#xff0c;数据采集早就成为一个广泛关注的热点话题&#xff0c;不论智能制造发展到何种程度&#xff0c;数据采集都是生产过程中应用非常频繁的需求&#xff0c;也是工业物联网不可或缺的一环。 利用工业数据采集系统…

处理机器学习数据集中字符串列(pandas.get_dummies)

如图&#xff0c;在数据集中week列的数据不是数值型&#xff0c;会导致我们在训练过程中难以处理。 而pandas库中有一个非常好用的函数&#xff0c;独热编码pandas.get_dummies(df) 使用此函数之后&#xff0c;会在原数据中新建各列代表Fri-Sun&#xff0c;值为0或1&#xff…

【大话Presto 】- 核心概念

文章目录 前言Operator Model And Iterator Model系统组成Connector数据模型查询执行模型StatementStageTaskSplitDriverOperatorExchangePipeLine 总结 前言 Presto&#xff08;PrestoDB&#xff09;是一个FaceBook开源的分布式MPP SQL引擎&#xff0c;旨在处理大规模数据的查…

全新的FL studio21.2版支持原生中文FL studio2024官方破解版

FL studio2024官方破解版是一款非常专业的音频编辑制作软件。目前它的版本来到了全新的FL studio21.2版&#xff0c;支持原生中文&#xff0c;全面升级的EQ、母带压线器等功能&#xff0c;让你操作起来更加方便&#xff0c;该版本经过破解处理&#xff0c;用户可永久免费使用&a…

「校园 Pie」 系列活动正式启航,首站走进南方科技大学!

PieCloudDB 社区校园行系列活动「校园 Pie」已正式启动。「校园 Pie」旨在促进数据库领域的学术交流&#xff0c;提供一个平台让学生们了解最新的数据库发展趋势和相关技术应用。 在「校园 Pie」系列活动中&#xff0c;PieCloudDB 社区将携拓数派技术专家&#xff0c;社区大咖…

可以免费使用的设计素材网站分享

UI设计师最怕什么&#xff1f; 没有创意&#xff0c;没有灵感&#xff0c;没有思路&#xff01; 在哪里可以得到idea&#xff1f;别担心&#xff0c;往下看&#xff01; 你知道网络有多大&#xff0c;你想要什么吗&#xff1f;今天&#xff0c;我想和大家分享一些宝藏网页设…

用户运营:如何搭建用户分析体系

在运营的工作范畴中&#xff0c;用户运营是很重要的一个环节&#xff0c;甚至有公司会设置专门的“用户运营”岗位。 用户运营的价值体现在多个方面&#xff0c;不仅可以帮助引流、吸引更多用户使用产品&#xff0c;在用户正式使用产品之后的运营则更为重要。通过日常用户运营&…