安卓并发编程基础

在这里插入图片描述

1.线程

1.线程与进程的区别

进程是程序运行和资源分配的基本单位,一个程序至少有一个进程,一个进程至少有一个线程。进程在执行过程中拥有独立的内存单元,而多个线程共享内存资源,减少切换次数,从而效率更高。线程是进程的一个实体,是cpu调度和分派的基本单位,是比程序更小的能独立运行的基本单位。同一进程中的多个线程之间可以并发执行。

2.创建线程的几种方式

  • 1.通过 new Thread的方式创建,可复写 Thread#run方法,Thread.start()方式启动。

  • 2.实现Runnable接口,通过Thread调用。

  • 3.实现 Callable 接口 ,封装 FutureTask 创建线程的 target 对象。
    在这里插入图片描述

可以获取线程的执行状态,get方法会阻塞线程,及取消线程。
对比:2 和 3 适合多个线程处理同一份资源的情况。

3.Android中异步任务的执行方式

  • new Thread

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

    • 轻量级异步任务工具,提供执行任务的进度回调给 UI 线程
    • 场景:适用于需要知道任务执行的进度,多个任务串行执行
    • 缺点:生命周期不同步,容易造成内存泄露,默认情况所有任务串行执行
    //1.串行执行,内部使用 SERIAL_EXECUTOR 执行任务
    AsyncTask.execute(runnable);
    AsyncTask.SERIAL_EXECUTOR.execute(runnable);
    //2.可并发执行的线程池
     AsyncTask.THREAD_POOL_EXECUTOR.execute(runnable);
    
  • HandlerThread

    • 适用于主线程需要和工作线程通信,持续性任务,比如轮询等场景,所有任务串行执行
    • 缺点:不会向普通线程一样主动销毁,需要手动销毁,否则造成内存泄露
  • IntentSerivice

    • 子线程执行任务,任务执行完后自我结束,不需要手动 stopService
  • ThreadPoolExecutor

    • 适用于处理大量耗时较短的任务场景
Executors.newCachedThreadPool();//线程可复用的线程池
Executors.newFixedThreadPool();//固定数量的线程池
Executors.newScheduledThreadPool();//可指定定时任务的线程池
Executors.newSingleThreadExecutor();//线程数量为1的线程池

4.线程的优先级

线程的优先级具有继承性,在某个线程中创建的线程会继承次线程的优先级。

  • JDK Api 限制了新设置的线程优先级为[1~10],优先级越高,获取 CPU 时间片的概率越高,UI 线程优先级为 5。
  • Android Api,可设置线程优先级为[-20 ~ 19],优先级越低,获取 CPU时间片的概率越高,UI为 -10。

5.线程的几种状态

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JGpP3c2o-1634264627400)(../../pic/1628091886021.png)]
在这里插入图片描述
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2FR1j3So-1634264627403)(../../pic/image-20210831155345858.png)]

2.线程并发安全

1.什么是线程安全?

线程安全的本质是能够让并发线程有序的运行 (这个有序有可能是先来后到的排队,有可能有人插队,不论怎样,同一时刻只能一个线程有访问同步资源),执行的结果,能够对其他线程可见。

2.线程安全的分类

  • synchronized 关键字
  • ReentrantLock 锁
  • AtomicInteger… 原子类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vIcfdShb-1634264627404)(../../pic/image-20211014192218978.png)]

3.锁的对比

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fydBy5IT-1634264627405)(../../pic/image-20211014192645562.png)]

  • 锁适合写操作多的场景,先加锁可以保证写操作的时数据的正确性。
  • 原子类适合读操作多的场景,不加锁的特点能够使其读操作性能大幅度提升。

3.如何保证线程安全

AtomicInteger 原子包装类,采用 CAS (Compare-And-Swap) 实现无锁的数据更新,自旋的设计能够有效避免线程因阻塞-唤醒带来的系统资源开销
适用场景:多线程计数,原子操作,并发数量小的场景

Volatile 关键字

volatile 修饰的成员变量在每次被线程访问的时候,都强迫从共享内存重新读取该成员变量的值,而且,当成员变量的值发生变化的时,强迫将变化的值重新写入共享内存中。

注意:不能解决非原子操作的安全性。性能不及原子类高。

volatile int count
public void increment(){
    //其他线程可见,原子操作
    count = 5;
    
    //非原子操作,其它线程不可见
    count = count + 1;
    count++;
}    

synchronized 关键字

锁 Java 对象,锁 Class 对象,锁同步代码块

  • 锁方法上,未获取到 对象锁的其他线程不可以访问该方法
synchronized void method(){}
  • 锁 Classs 对象,加在 static 方法上相当于给 Class 对象加锁,哪怕是不同的 Java对象实例。也需要排队执行
synchronized static void method(){}
  • 锁代码块上,未获得对象锁的线程可以同步执行代码块之外的代码
void method(){
    Log.i(TAG,"code out before the synchronized");
    synchronized(this){
        
    }
}

synchronized 的优劣势

优势:

  • 如果同步方法中出现了异常,Jvm 也能够为我们自动释放锁,从而避免死锁,不需要开发者手动释放锁

劣势:

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

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

  • 基本用法
ReentratLock lock = new ReentratLock();
try{
    lock.lock();
    ....
}finally{
    locak.unLock();
}
void lock();//获取不到会阻塞
boolean tryLock();//尝试获取锁,成功返回 true
boolean tryLock(3000,TimeUnit.MILLISECONDS);//在一定时间内不断尝试去获取锁
void lockInterruptibly();//可使用Thread.interrupt()打断阻塞状态,退出竞争,让给其他线程
  • 可重入,避免死锁
ReentratLock lock = new ReentratLock();
public void doWork(){
    try{
    	lock.lock();
    	doWork();//递归调用,使得同一线程多次获取锁
	}finally{
    	locak.unLock();
	}
}
  • 公平锁 与 非公平锁

    • 公平锁:所有进入阻塞的线程排队一次均有机会执行
    • 默认非公平锁:允许线程插队,避免每一个线程都进入阻塞,在唤醒,性能高。因为线程可以插队,导致队列中可能会存在线程饿死的情况,一直得不到执行。
  • Condition 条件对象

    • 可以使用 awit-singal 指定唤醒一个(组)线程。相比于 wait-notify 要么全部唤醒,要么只能唤醒一个,更加灵活
    ReentrantLock lock = new ReentrantLock();               
    Condition worker1 = lock.newCondition();                
    Condition worker2 = lock.newCondition();                
                                                            
    class Worker1{                                          
        ....                                                
        worker1.await();//进入阻塞,等待唤醒                         
        ....                                                
    }                                                       
                                                            
    class Worker2{                                          
        ....                                                
        worker2.await();//进入阻塞,等待唤醒                         
        ....                                                
    }                                                       
                                                            
    class Boss{                                             
                                                            
        if(...){                                            
            worker1.signal();//指定唤醒线程1                      
        }else{                                              
            worker2.signal();//指定唤醒线程2                      
        }                                                   
    }                                                       
    

4.线程池

为什么引入线程池?

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

Java中默认的线程池。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MUy3GsH6-1634264627406)(../../pic/1628176650583.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jdne6lCQ-1634264627407)(../../pic/1628176667371.png)]

JUC包下 Executors 提供的几种线程池

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Xyy2yfT5-1634264627408)(../../pic/image-20211015101745157.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-odV0mdlH-1634264627409)(../../pic/1628176788183.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IovVtSex-1634264627410)(../../pic/1628176879217.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Y0xWSzHF-1634264627410)(../../pic/1628176954923.png)]

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【完整课程列表】 资源汇总下载地址:https://download.csdn.net/download/qq_27595745/55418618 Java SE编程入门教程 collection与collections(共7页).pptx Java SE编程入门教程 java GC(共6页).pptx Java SE编程入门教程 java instanceof(共3页).pptx Java SE编程入门教程 java IO(共28页).pptx Java SE编程入门教程 java Math(共11页).pptx Java SE编程入门教程 java object(共9页).pptx Java SE编程入门教程 java static final(共24页).pptx Java SE编程入门教程 java this和super(共10页).pptx Java SE编程入门教程 java 常用API(共22页).pptx Java SE编程入门教程 javaGUI编程快速入门(1)(共82页).pptx Java SE编程入门教程 java包装器(共9页).pptx Java SE编程入门教程 java反射机制(共16页).pptx Java SE编程入门教程 java泛型(共11页).pptx Java SE编程入门教程 java封装继承多态(共56页).pptx Java SE编程入门教程 java集合(共38页).pptx Java SE编程入门教程 java接口(共21页).pptx Java SE编程入门教程 java类和对象方法以及包的使用(共56页).pptx Java SE编程入门教程 java类和对象方法以及包的使用(共62页).pptx Java SE编程入门教程 java判断循环(共79页).ppt Java SE编程入门教程 java入门以及变量debug(共63页).pptx Java SE编程入门教程 java设计模式(共17页).pptx Java SE编程入门教程 java数组(共33页).pptx Java SE编程入门教程 java网络编程(共29页).pptx Java SE编程入门教程 java线程(共61页).pptx Java SE编程入门教程 java序列化(共14页).pptx Java SE编程入门教程 java异常(共57页).pptx Java SE编程入门教程 java正则(共8页).pptx Java SE编程入门教程 properties(共3页).pptx Java SE编程入门教程 String字符串(共27页).pptx Java 位运算.docx java正则表达式例子大全 共10页.doc JAVA正则表达式实例教程 共17页.docx JAVA正则表达式实例教程 共17页.pdf 递归算法.docx 堆和栈.wps

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值