1.线程和进程的区别
线程:是程序调度和执行的最小单元,包含在进程之中,负责具体的任务执行
进程:系统进行资源分配的基本单位,负责资源的整体管理和调度
2.为什么要使用多线程
在android系统中,一个程序只有一个主线程,即UI线程。如果全部在一个线程中执行代码,就必须等前面的任务执行完,才执行后面的任务,而主线程不能进行耗时操作,否则会引起ANR、卡顿等问题,所以需要创建多个子线程去完成耗时任务
3.实现多线程的几种方式
4种:继承Thread类、实现Runnable接口、使用AsyncTask类、使用Executors
4.线程之间的通信方式
Handler、AsyncTask、BroadCastReceiver、线程同步机制、EventBus、RxJava、Kotlin协程
5.并发和并行
并发和并行表示CPU执行多个任务的方式,单核CPU只能做到并发,多核CPU才可以做到并行
并发:在同一段时间内,多个程序在同一个CPU完成了从开始到结束的动作,就可以说这几个程序是并发的
并行:当有多个CPU时,当一个内核执行一个进程时另一个内核执行另一个进程时,两个进程互不抢占资源,这种方式为并行
6.同步和异步
同步:发送方发出数据后等待接收方响应后才发出下个数据包的通讯方式
异步:发送方发出数据后不等待接收方相应就发出下个数据包的通讯方式
7.说说Handler的作用,为什么要用Handler机制
将工作线程需要更新UI的操作信息传递到主线程从而实现对UI的更新。因为主线程不能做耗时操作,子线程不能更新UI
8.保证线程并发安全的正确性的关键是什么?
原子性:一个或多个操作要么全部执行并且执行过程不被打断,要么就都不执行。例如Java中基本数据类型变量的读取和赋值操作
可见性:多个线程访问同一个变量时,其中一个线程修改了变量的值,其他的线程能够立即看到修改的值。
有序性:程序执行的顺序按照代码的先后顺序执行。在Java内存模型中,允许编译器和处理器对指令进行重排序,而这个重排序过程不会影响到单线程程序的执行,却会影响到多线程并发执行的正确性
9.为什么会出现线程安全问题
Java内存模型规定所有的变量都存储在主内存中,每个线程有自己的工作内存。
线程对变量的所有操作都必须在工作内存中进行,而不能直接读写主内存。
线程访问一个变量,首先将变量从主内存拷贝到工作内存,对变量的写操作不会马上同步到主内存
线程之间无法直接访问对方工作内存中的变量,线程间变量的传递需要自己的工作内存和主内存进行数据同步
10.怎么解决线程安全问题
volatile修饰共享变量保证可见性
普通的共享变量被修改后,什么时候写入主存是不确定的,其他线程去读取时可能还是原来的值。
当共享变量被volatile修饰时可以保证修改的值立即更新到主存
Synchronized同步锁保证可见性和原子性
ThreadLocal从不共享变量的角度来保证线程安全
使用ThreadLocal管理变量,每个线程持有独立的变量副本,每个线程对自己的变量副本进行修改,不影响其他线程
11.volatile和synchronized的区别
volatile只能修饰变量,synchronized可以修饰变量、方法和类
volatile不会造成线程阻塞,synchronized会造成线程阻塞
volatile标记的变量不会被编译器优化,synchronized标记的变量会被编译器优化
12.什么是线程死锁
死锁指的时多个线程因竞争资源而造成的一种僵局(互相等待)
13.死锁产生的原因
系统资源的竞争
系统中拥有的不可剥夺资源数量不满足多个进程运行的需要,使得进程在运行过程中因争夺资源而陷入僵局,只有对不可剥夺资源的竞争才可能产生死锁,对可剥夺资源的竞争不会引起死锁
进程推进顺序非法
进程在运行过程中,请求和释放资源的顺序不当,也会导致死锁
信号量使用不当
进程间彼此相互等待对方发来的消息,使得这些进程无法继续向前推进
死锁产生的必要条件
必须同时满足以下四个条件,死锁才会产生:
互斥条件:进程要求对所分配的资源进行排他性控制,即在一段时间内某资源仅为一个进程所占有,此时若有其他进程请求该资源只能等待
不剥夺条件:进程所获得的资源在未使用完毕之前不能被其他进程强行夺走,只能获得该资源的进程自己主动释放
请求和保持条件:进程已经持有了至少一个资源,但又提出新的资源请求,而该资源被其他进程占有,此时请求进程被阻塞,但对自己已获得的资源保持不放
等待条件:存在一种进程资源的循环等待链,链中每一个以获得资源的进程同时被链中下一个进程所请求