android wait函数,Android-HandlerThread中wait/notify/notifyall的理解

最近在阅读HanlerThread源码时在getLooper中有wait函数,在run中用到了notifyall函数。于是就思考这两个函数的作用是什么?为什么需要在这里添加这两个函数?经过一番研究终于理解了,这边做一个总结。

/**

* This method returns the Looper associated with this thread. If this thread not been started

* or for any reason isAlive() returns false, this method will return null. If this thread

* has been started, this method will block until the looper has been initialized.

* @return The looper.

*/

public Looper getLooper() {

if (!isAlive()) {

return null;

}

// If the thread has been started, wait until the looper has been created.

synchronized (this) {

while (isAlive() && mLooper == null) {

try {

wait();

} catch (InterruptedException e) {

}

}

}

return mLooper;

}

@Override

public void run() {

mTid = Process.myTid();

Looper.prepare();

synchronized (this) {

mLooper = Looper.myLooper();

notifyAll();

}

Process.setThreadPriority(mPriority);

onLooperPrepared();

Looper.loop();

mTid = -1;

}

从消费者生产者模式说起

为了理解wait/notify/notifyall的作用和关系,首先通过消费者生产者设计模式为例来介绍。什么是生产者消费者?简单来说就是为了保持供需平衡的一种手段。生产者在发现仓库里面没有货物了再去生产,当生产到一定数量之后就停止生产,并告诉消费者有货了你可以过来消费了;而消费者会不断从仓库中消费货物,如果没有了就等待,并告诉生产者快去生产货物。这样做的好处就是货物不会堆积,保证供需平衡。经典的生产者消费者模式代码如下所示:

// 生产者

public class Producer implements Runnable {

List products;

public Producer(List products) {

this.products = products;

}

@Override

public void run() {

while (true) {

produce();

}

}

private void produce() {

synchronized (products) {

try {

// 当仓库产品数量到达1个时停止生产。

// 调用wait()当前线程释放锁,并进入等待池队列

while (products.size() == 1) {

products.wait();

}

Thread.sleep(1000);

cache.add(1);

// 通知消费者消费产品。

cache.notify();

}

catch (Exception e) {

e.printStackTrace();

}

}

}

}

// 消费者

public class Consumer implements Runnable {

List products;

public Consumer(List products) {

this.products = products;

}

@Override

public void run() {

while (true) {

consume();

}

}

private void consume() {

synchronized (products) {

try {

// 当仓库为空时,停止消费。

// 调用wait()当前线程释放锁,并进入等待池队列

while (products.isEmpty()) {

products.wait();

}

cache.remove(0);

// 通知生产者生产产品

cache.notify();

}

catch (Exception e) {

e.printStackTrace();

}

}

}

}

在结合生产者消费者模式的代码分析之前先介绍一下等待池和锁池。

等待池:当一个线程调用某对象的wait方法,该线程就会释放该对象的锁,并进入该对象的等待池队列。

锁池:当一个线程已经拥有一个对象的锁时,其他线程想要进入该对象的synchronized的方法,就必须先获得这个对象的锁,但是该对象的锁已经被线程拥有,因此其他对象就会进入该对象的锁池。

生产者和消费者各自开启一个线程进行处理,当调用wait时,其实是将当前线程的锁释放,并进入该锁的等待池队列。而调用notify可以将该对象的等待池队列中随机一个线程唤醒进入锁池,去竞争该对象的锁。而调用notifyall可以将该对象的等待池队列中所有线程都移入该对象的锁池,去竞争该对象的锁。这里注意到一种可能引起死锁的情况:

假如有一个生产者P1和两个消费者C1 C2

1 消费者C1 C2发现仓库为空,都进入等待池。

2 P1 生产一个产品后,也进入等待池,并唤醒等待池中的C2,C2进入锁池去竞争该对象的锁。

3 C2 竞争到该锁,并消费了产品再次进入等待池,并随机唤醒一个等待池的线程,假如唤醒的是C1。

4 C1检测到当前仓库为空,直接进入等待池。这时候P1 C1 C2都在等待池中,没有人来唤醒他们,就造成了死锁。

假如用notifyAll就不会出现这种情况。因为如果使用notifyall,在第三步中C2会把C1和P1一起唤醒,即便C1检测到当前仓库为空,P1也会开始生产产品,不会造成死锁。

HandlerThread中wait和notifyall的使用

理解了wait/notify/notifyall的作用之后,再回过头来看HandlerThread中为什么在run函数中需要用到notifyall。

首先我们来看getHandlerLoop函数。首先判断这个looper所在线程是否启动,如果启动则进入同步块。在同步块中判断如果looper还没有创建成功,就将该线程移入等待池.直到run中得到looper之后调用notifyall唤醒该线程,从而得到looper.因此这里使用wait/notifyall来解决同步问题,保证只有线程创建成功并且looper创建成功才能得到looper.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值