【Android】Handler(四)Looper的相关知识点

Handler 机制是 Android 多线程间通信的一种常见方式。每个 Handler 对象由一个 Looper 和一个 MessageQueue 组成,用于将 Message 对象处理到指定的线程中。通过创建 Handler 实例,在子线程中创建 Message 对象并通过sendMessage()方法发送给 Handler,然后 Handler 会接收到消息并处理它。最后,Handler 在处理完消息后会将消息回传至主线程,再通过dispatchMessage()方法交由UI线程处理。


Looper 中在每一个线程上只有一个

ThreadLocal

线程是一个程序中执行的一条执行路径。每个线程都拥有自己的栈空间和寄存器等资源,因此它们之间是互相独立的。为了避免在多线程环境下出现资源竞争、数据不一致等问题,需要对线程之间的访问进行隔离和控制。其中一个解决方案就是使用 ThreadLocal。

ThreadLocal 是一个 Java 中的类,它可以在每个线程中存储和获取与其他线程隔离的变量值。具体来说,每个 ThreadLocal 对象都会存储到当前线程的 ThreadLocalMap 中。ThreadLocalMap 是一个以 ThreadLocal 对象为键、以变量值为值的 Map,它可以快速地访问和获取每个线程所拥有的 ThreadLocal 变量的值。当一个线程结束时,它所持有的 ThreadLocalMap 也会随之销毁。

在 Android 中,Looper 是一个消息循环机制,它可以让线程在消息队列中等待并处理消息。每个 Looper 对象都对应一个消息队列(MessageQueue)和一个函数(loop()),它可以不断地从消息队列中取出消息进行处理。

当我们调用 Looper.prepare() 方法时,该方法会为当前线程创建一个新的 Looper 对象。在 prepare() 方法内部,Looper 会将当前线程的 Looper 对象存储在一个名为 sThreadLocal 的 static 变量中。这个变量是一个 ThreadLocal 对象,这个变量是一个 ThreadLocal 对象,它可以在每个线程中存储和获取与其他线程隔离的变量值。由于 sThreadLocal 是一个 static 变量,所以它在整个应用程序中只存在一个实例,但是每个线程都可以通过这个变量来访问和管理自己的 Looper 对象。

具体来说,sThreadLocal 变量会存储到当前线程的 Thread 类中的 ThreadLocalMap 中。当我们需要使用某个线程的 Looper 对象时,只需要调用 Looper.myLooper() 方法即可获取当前线程所对应的 Looper 对象。这个方法会先获取当前线程的 ThreadLocalMap,然后从中获取到 sThreadLocal 变量对应的值,也就是当前线程的 Looper 对象。

通过使用 sThreadLocal 变量和 ThreadLocalMap,Looper 可以实现多线程之间的隔离和独立,确保每个线程都有自己的 Looper 对象。这个机制是 Android 框架中异步消息传递机制的核心之一,也是实现各种异步操作的基础。


Looper 的阻塞

Looper 中有两个方面的阻塞:

Message 不到时间,空转等待:

在某些情况下,Message 还没到执行时间之前,Looper 会一直进行循环,不断地空转等待,直到 Message 到了执行时间才继续执行。这种情况下,Looper 并没有真正的阻塞,它只是在等待 Message 到来。

MessageQueue 为空,阻塞等待:

如果 MessageQueue 中没有消息,那么 Looper 会进入阻塞状态,等待新的消息到来。这个过程中,Looper 对 CPU 的占用率非常低,因此不会对系统性能产生过大的影响。

需要注意的是,第二种情况可能会导致线程进入无限等待状态,从而造成应用程序的假死或 ANR(Application Not Responding)错误。


Looper设计模式

Looper 使用了生产者-消费者设计模式,其中 MessageQueue 充当生产者,Looper 的 loop() 方法充当消费者。

具体来说,MessageQueue 维护了一个消息队列,消息队列中的消息相当于生产者生产出来的产品,Looper 对消息队列进行消费和处理。在这个过程中,MessageQueue 和 Looper 之间是解耦的,它们可以独立地进行操作和管理。

当 MessageQueue 中产生新的消息时,它会将消息加入到消息队列的尾部,并通知 Looper 轮询消息队列。Looper 取到消息后,会依次对每个消息进行分发和执行,直到消息队列为空。整个过程中,MessageQueue 和 Looper 都不需要关心对方的具体实现细节,只需要按照约定好的协议进行数据传输和处理。

这种设计模式的优点是可以有效地降低耦合度,并提高代码的可读性和维护性。通过将生产者和消费者分离,我们可以更灵活地添加或修改消息的生产和消费方式,而无需对整个系统进行大规模的修改。同时,在多线程环境下,生产者和消费者之间的协作也可以有效避免竞争和冲突,保证了系统的线程安全性。


synchronized

Looper 中使用了 synchronized 关键字来实现线程之间的同步。具体来说,Looper 中的 loop() 方法和 MessageQueue 中的 enqueueMessage() 方法都是加了 synchronized 关键字的方法,它们在执行时都会获取 MessageQueue 对象的锁,确保同一时刻只能有一个线程访问和修改 MessageQueue。

这种同步机制是为了避免多个线程同时操作 MessageQueue 时产生的竞争和冲突。在 Android 系统中,生产者和消费者之间是通过 Message 消息进行通信的,因此必须保证 MessageQueue 中的消息能够正确地被分发和执行。如果没有同步机制,就会出现多个线程同时向 MessageQueue 中添加消息或者同时取出并处理消息的情况,从而导致数据不一致性和程序崩溃等问题。

例如:

Looper.prepare() 方法中创建和初始化 Looper 对象时,会加锁。由于每个线程只有一个 Looper 实例,因此需要确保在创建新的 Looper 实例的同时,不会出现多个线程同时执行该方法的情况。

Looper.loop() 方法中执行消息循环时,会加锁。该方法会不断地从 MessageQueue 中取出消息进行分发和执行,如果不加锁就会出现多个线程同时访问和修改 MessageQueue 的情况,从而导致数据一致性和程序错误。

MessageQueue.enqueueMessage() 方法中添加消息到 MessageQueue 时,会加锁。该方法会将新消息添加到 MessageQueue 的尾部,并通知正在等待消息的线程有新的消息可用。如果不加锁就会出现多个线程同时向 MessageQueue 添加消息的情况,可能导致消息顺序错乱或者丢失。

MessageQueue.next() 方法中获取下一个要处理的消息时,会加锁。该方法会从 MessageQueue 的头部取出下一个要处理的消息,并返回给调用者。如果不加锁就会出现多个线程同时取出并执行同一条消息的情况,可能导致数据的不一致性和程序的错误。


Looper 使用 synchronized 原因:

执行效率:

synchronized 是 Java 中最基本和常用的同步机制,由 JVM 内部实现,可以比较方便地保证线程安全。相对于其他的锁实现,synchronized 的执行效率相对较高,避免了过多的性能开销。

粒度控制:

在 Looper 的实现中,使用 synchronized 关键字可以比较方便地控制锁的粒度,避免了锁定过大的代码块或方法,从而提高了并发性能。如果使用其他类型的锁,可能会存在锁竞争或死锁,影响程序正确性和性能。

可重入性:

synchronized 是可重入锁,即一个线程在持有锁的情况下还可以重复获取锁,而不会出现死锁或其他的异常。在 Looper 中,需要实现消息循环并处理消息时可能需要多次进入锁定代码块或方法,因此使用可重入锁可以避免代码逻辑出错。

synchronized 是 Java 中最基本和常用的同步机制,而且在大多数情况下可以提供良好的并发性能和可靠性。对于轻量级的同步需求,synchronized 是不错的选择。


Handler线程间通信机制通过什么实现

Handler 是一种消息处理机制,它提供了一种在不同线程之间进行通信的方式。由于·Handler 是在同一个进程中创建的,因此它们可以共享进程中的内存,从而实现线程间的通信

当我们在一个线程中创建 Handler 时,这个 Handler 会与当前线程中的 Looper 绑定,并创建一个 MessageQueue 对象。然后,我们可以使用这个 Handler 向该线程中的 MessageQueue 发送消息(即构造 Message 对象并添加到该队列中),这些消息就会被 Looper 接收并交给对应的 Handler 进行处理。

当我们需要在其他线程中发送消息时,就需要使用 Handler 的 post 方法或者 sendMessage 方法,这些方法会将要发送的消息封装成一个 PendingMessage 对象,并加入到目标线程的消息队列中。最终,目标线程中的 Looper 会将这个 PendingMessage 对象转化成 Message 对象,并交给绑定的 Handler 进行处理。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值