- 多线程
线程是一种轻量级的执行单元,它可以在应用程序中执行并发任务。
多线程是指在同一时间内执行多个线程。在Android中,多线程可以帮助我们更好地管理应用程序的资源和响应性能。
- 线程池
线程池是一种用于管理线程的机制,它可以帮助我们更好地管理线程的创建和销毁。线程池可以在需要时创建线程,并在不需要时销毁线程,从而减少了线程创建和销毁的开销。
- 项目中典型多线程场景
主线程
主线程是UI线程,它负责处理用户界面的事件和更新UI。主线程包括以下任务: 1) 处理用户界面事件:主线程负责处理用户界面事件,例如点击按钮、滚动屏幕等。当用户执行这些操作时,Android系统会将事件发送到主线程,主线程会处理这些事件并更新UI。
-
更新UI:主线程负责更新UI,例如更改文本、更改颜色、添加或删除视图等。当我们在代码中更改UI时,这些更改都必须在主线程中执行。
-
处理生命周期事件:主线程负责处理Activity和Fragment的生命周期事件,例如创建、启动、暂停、恢复和销毁。这些事件都必须在主线程中执行。
-
处理广播事件:主线程负责处理广播事件,例如网络状态变化、电池电量变化等。当这些事件发生时,Android系统会将它们发送到主线程,主线程会处理这些事件并执行相应的操作。
-
处理异步任务:主线程负责处理异步任务的结果。当我们执行异步任务时,任务的结果会在主线程中返回,并在主线程中处理。 需要注意的是,如果我们在主线程中执行耗时操作,例如网络请求或数据库查询,会导致UI线程阻塞,从而导致应用程序响应性能下降。因此,我们应该将这些操作放在后台线程中执行,以避免阻塞UI线程
蓝牙/sensor消息
接收消息、处理消息在两个线程
- 波形绘制
Retrofit中的线程
在Retrofit中,我们可以使用Call接口来管理线程。Call接口提供了enqueue()方法来执行异步请求,也提供了execute()方法来执行同步请求。在异步请求中,Retrofit会自动将请求放在一个新的线程中执行,而在同步请求中,请求将在当前线程中执行。如果我们需要在请求中指定线程,可以使用Call接口的enqueue()方法的重载版本,该版本接受一个Callback对象和一个Executor对象作为参数,我们可以在Executor对象中指定线程池来执行请求。
同步请求execute():
异步请求:
RxJava中的线程
在RxJava中,线程的管理是通过调度器(Scheduler)来实现的。调度器是一个抽象的概念,它定义了任务在哪个线程上执行的规则。RxJava提供了多种不同的调度器,包括: - Schedulers.io():用于执行I/O操作的线程池,适用于网络请求、文件读写等操作。 - Schedulers.computation():用于执行计算密集型操作的线程池,适用于CPU密集型的操作,如图像处理、加密解密等。 - Schedulers.newThread():每次都会创建一个新的线程,适用于需要立即执行的任务。 - AndroidSchedulers.mainThread():用于在Android主线程上执行任务,适用于更新UI等操作。 在RxJava中,我们可以使用subscribeOn()和observeOn()方法来指定任务的执行线程。subscribeOn()方法用于指定任务的订阅线程,而observeOn()方法用于指定任务的观察线程。例如,下面的代码将任务的订阅线程指定为IO线程,观察线程指定为主线程。
Observable.just("Hello, world!")
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe { text -> textView.text = text }
这样,当我们订阅这个Observable时,它会在IO线程上执行,然后在主线程上观察结果并更新UI。这种方式可以避免在主线程上执行耗时操作,从而提高应用程序的响应速度和用户体验。
- android常见多线程场景、线程的启动和停止
Thread创建的多个线程
AsyncTask
Handler
ThreadPoolExecutor
- 线程安全问题
-
竞态条件:竞态条件是指多个线程同时访问共享资源,导致结果依赖于线程执行的顺序。这可能会导致不一致的结果或错误的行为。
-
死锁:死锁是指多个线程互相等待对方释放资源,导致所有线程都无法继续执行。这可能会导致应用程序挂起或崩溃。
-
活锁:活锁是指多个线程在尝试解决死锁问题时,不断地重试导致无法继续执行。这可能会导致应用程序挂起或崩溃。
-
内存一致性错误:内存一致性错误是指多个线程同时访问共享内存,导致内存中的数据不一致。这可能会导致不一致的结果或错误的行为。
措施:
-
使用同步机制:同步机制可以帮助我们控制多个线程对共享资源的访问。在Java中,我们可以使用synchronized关键字或Lock接口来实现同步。
-
避免死锁:为了避免死锁,我们可以使用避免策略,例如按照相同的顺序获取锁,或者使用超时机制。
-
避免活锁:为了避免活锁,我们可以使用随机化策略,例如在等待锁时随机等待一段时间。
-
使用原子操作:原子操作可以帮助我们避免内存一致性错误。在Java中,我们可以使用Atomic类来实现原子操作。