Android之多线程,包括线程、Java同步问题、阻塞队列、线程池、AsyncTask、HandlerThread、IntentService等内容。
本文是我一点点归纳总结的干货,但是难免有疏忽和遗漏,希望不吝赐教。
转载请注明链接:https://blog.youkuaiyun.com/feather_wch/article/details/79132183
有帮助的话请点个赞!万分感谢!
Android多线程(88题)
版本号: 2018/9/18(10:10)
文章目录
问题汇总
线程(13)
1、什么是进程
- 系统分配资源的最小单位
- 进程就是程序运行的实体
2、什么是线程
- 系统调度的最小单位
- 一个进程中可以包含多个线程
- 线程拥有各自的计数器、堆栈和局部变量等属性,能够访问共享的内存变量
3、线程的好处
- 比进程的资源消耗要小,效率要更高
- 多线程的并发性能减少程序的响应时间
- 多线程能简化程序的结构,使程序便于理解和维护
4、线程的状态有哪些?
| 状态 | 解释 | 备注 |
|---|---|---|
| New | 新创建状态 | 线程已被创建,还未调用start,做一些准备工作 |
| Runnable | 可运行状态 | start之后进入,Runnable线程可能在运行也可能没有在运行,取决于系统分配的时间 |
| Blocked | 阻塞状态 | 线程被锁阻塞,暂时不活动 |
| Waiting | 等待状态 | 线程不运行任何代码,消耗最少的资源,直至调度器激活该线程 |
| Timed Waiting | 超时等待状态 | 与Waiting不同在于,可以在指定时间内返回 |
| Terminated | 终止状态 | 当前线程执行完毕:可能是run运行结束,或者出现未能捕获的异常导致线程终止 |
5、线程如何从新建状态进入可运行状态?
Thread.start()
6、线程如何从可运行状态到阻塞状态
- 线程在
请求锁的时候会进入阻塞状态- 线程一旦
得到锁会返回到可运行状态
备注:
如下题目中的
Object.wait()是指具体对象调用wait等方法---someObject.wait(),Thread.join是指具体线程调用该方法—childThread.join()
7、线程如何从可运行状态切换到等待状态
- 进入等待:
Object.wait()---当前线程进入等待状态(当前线程需要已经获得过锁,且调用后会失去锁)、Thread.join()---父线程会等待子线程- 退出:
Object.notify()和Object.notifyAll()
8、线程如何从可运行状态切换到超时等待状态
- 进入:
Thread.sleep(long)、Thread.join(long)---让父线程等待子线程,子线程结束后父线程才继续执行、Object.wait(long)- 退出:
Object.notify()、Object.notifyAll()或者超时退出
9、线程如何从可运行状态切换到终止状态
- 执行完毕
- 异常退出
10、Object.notify()、Object.notifyAll()之间的区别
Object.notify(): 随机唤醒一个wait线程,调用该方法后只有一个线程会由等待池进入锁池。
Object.notifyAll(): 会将对象等待池中的所有线程都进入锁池,进行竞争。竞争到的线程会继续执行,在释放掉对象锁后,锁池中的线程会继续开始竞争。(进入到锁池的线程,不会再进入等待池)
11、等待池和锁池是什么?
等待池:线程调用对象的wait方法后,会释放该对象的锁,然后进入到该对象的等待池中。锁池:线程想要获得对象的锁,但是此时锁已经被其他线程拥有,这些线程就会进入到该对象的锁池中。
12、创建线程的三种方法
- 继承Thread,重写run方法
- 实现Runnable接口,并实现该接口的run方法
- 实现Callable接口(Executor框架中的内容,优势是能在任务结束后提供一个返回值,Runnable无法这样做),重写call方法。
- 推荐第二种
Runnable接口的方法,因为继承Thread没有必要。
13、终止线程的两种方法
- 调用
Thread.interrupted()设置中断标志位,并通过Thread.currentThread().isInterrupted()检查标志位。缺点:被中断的线程不一定会终止- 在
run()方法中设置boolean标志位(需要volatile修饰为易变变量):条件满足时跳出循环,run运行结束,thread安全终止
14、实现Callable接口创建多线程
1-实现Callable接口,重写run方法。
2-使用FutureTask进行包装,并且执行
// 1、实现Callable接口,并用futureTask包装。
FutureTask<Integer> futureTask = new FutureTask<>(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
// TODO sth,并返回结果。
Integer result = 1;
return result;
}
});
// 2、开启线程并且执行任务
Thread thread = new Thread(futureTask);
thread.start();
// 3、获取到线程执行的返回值
Integer result = futureTask.get();
同步(8)
1、重入锁是什么?(3)
- 重入锁ReentrantLock在Java SE 5.0引入
- 该锁支持一个线程对资源的重复加锁
- 一个线程在锁住锁对象后,其他任何线程都无法进入Lock语句
val mLock = ReentrantLock()
mLock.lock()
try {
//需要同步的操作
}finally {
mLock.unlock() //finally中进行解锁,避免死锁问题
}
2、可重入锁的用途?
阻塞队列就是使用ReentrantLock实现的。
3、条件对象/条件变量的作用(4)
- 用于管理那些获得锁却因部分条件不满足而无法正常工作的线程
- 可以通过
newCondition获得锁lock的条件变量(和ReentrantLock配合使用)- 条件对象调用
await方法,当前线程就会阻塞并且放弃该锁await线程会进入阻塞状态,直到另一个线程,调用同一条件对象的signalAll()方法,之后等待的所有线程通过竞争条件去抢锁
//1. 可重入锁
val mLock = ReentrantLock()
mLock.lock()
//2. 条件变量
val condition = mLock.newCondition()
try {
while(条件不满足){
//3. await进入Block状态
condition.await()
}
//4. 条件满足方会进行后续操作
//...
//5. 操作完成后调用同一条件变量的signalAll去激活等待该条件的线程
condition.signalAll()
}finally {
mLock.unlock() //finally中进行解锁,避免死锁问题
}
4、synchronized同步方法(4)
Lock和condition提供了高度的锁定控制,然而大多数情况下不需要这样麻烦- 从Java 1.0开始,每个对象都有一个内部锁
- 当一个方法使用
synchronized修饰,意味着线程必须获得内部锁,才能调用该方法
synchronized public void doSth() throws InterruptedException{
//1. 条件不满足,进入Block状态
while(条件不满足){
wait();
}
//2. 条件满足方会进行后续操作
//...
//3. 解除该锁,并通知所有阻塞的线程
notifyAll();
}
- 备注:Kotlin学的不深,暂时没找到Kotlin中同步的方法,就用Java实现
5、同步代码块的使用(1)和问题(2)
- java中可以通过给一个Object对象上锁,来使用代码块
- 同步代码块非常脆弱不推荐
- 一般实现同步,最好使用
java.util.concurrent包下提供的类,例如阻塞队列
Object object = new Object();
synchronized (object){
//进行处理, 不推荐使用
}
6、synchronized方法和synchronized同步代码块的区别?
用synchronized修饰符修饰的方法就是同步方法synchronized代码块需要一个对象锁
7、死锁是什么?
死锁是指两个或者两个以上线程/进程进行资源竞争时出现了阻塞现象,如果没有外力帮助,它们都将无法继续工作下去,此时系统处于死锁状态。
8、可能出现死锁的场景
可重入锁ReentrantLock在mLock.lock()后如果出现异常,但是没有在try-catch的finally中没有执行mLock.unLock()就会导致死锁。notify比notifyAll更容易出现死锁
Java中的volatile(13)
1、Java的堆内存是什么?(2)
- 堆内存用于存储
对象实例- 堆内存被所有线程所共享: 会存在内存可见性问题
2、 Java中的局部变量、方法定义的参数是否会被线程所共享?
- 局部变量、方法定义的参数则不会在线程间共享:不存在内存可见性问题,也不会受到内存模型影响,
3、Java内存模型的作用
- Java内存模型控制线程之间的通信,
决定了一个线程对共享内存的写入何时对另一个线程可见。定义了线程和主存之间的抽象关系:
- 线程之间的共享变量存储在
主存中,每个线程都有一个私有的本地内存,本地内存中存储了该该线程贡献变量的副本,本地内存是Java内存模型中的抽象概念,实际上并不存在,覆盖了缓存、写缓存区、寄存器等区域。
4、Java内存模型图

本文详细探讨了Android中的多线程,涵盖线程、同步、Java中的volatile、阻塞队列和线程池等主题。通过88道问题,作者深入剖析了各个概念和应用场景,包括线程的状态转换、重入锁、volatile关键字的作用、阻塞队列的工作原理以及线程池的创建和使用。此外,还介绍了线程间的通信、同步问题以及避免死锁的策略。
最低0.47元/天 解锁文章
1200

被折叠的 条评论
为什么被折叠?



