Android Handler消息机制03-Message源码学习

0. 系列文章汇总

1.关键机制说明

1.1分发机制

分发是在Looper.loop()会在for循环中不停地从Message Queue中取出消息,并调用消息对应的Handler对象的dispatchMessage方法,详细执行见源码
其对于处理Message三种方法,且有优先级:

  1. 当Message的回调方法不为空时,则回调方法msg.callback.run(),其中callBack数据类型为Runnable,否则进入步骤2;
  2. 当Handler的mCallback成员变量不为空时,则回调方法mCallback.handleMessage(msg),否则进入步骤3;
  3. 调用Handler自身的回调方法handleMessage(),该方法默认为空,Handler子类通过覆写该方法来完成具体的逻辑。
    /**
     * 处理系统消息,在Looper.loop(),当发现有消息时,会调用消息的目标Handler,执行此方法来分发消息
     */
    public void dispatchMessage(@NonNull Message msg) {
        if (msg.callback != null) {
            // 当Message存在回调方法时,回调msg.callback.run()方法
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                // 当Handler存在callback成员变量时,回调callback的handleMessage方法
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            // 执行Handler自身的回调方法handleMessage
            handleMessage(msg);
        }
    }

1.2 消息发送机制

在Handler 有各种类型的发送消息的机制,有实时发送(例如:sendMessage(@NonNull Message msg),延时相对时间发送(sendMessageDelayed(@NonNull Message msg, long delayMillis)),指定绝对时间发送(sendMessageAtTime(@NonNull Message msg, long uptimeMillis))等,但是实际上最终调用queue.enqueueMessage方法
在这里插入图片描述
需要重点注意的时间,延时是通过SystemClock.uptimeMillis() 加上延时时间来计算的。SystemClock 有一个特点是在手机休眠时间是不计时的,所以在后台执行时有可能会实际执行比指定延时时间delayMillis更长

2. 问题

  • Q: Handler 、MessageQueue、Looper和线程分别是什么关系?
    A: 一个线程只有一个Looper,通过ThreadLocal实现,且也只对应一个MessageQueue,但是可以有多个Handler。Message对象会关联一个Handler对象,message.target,Handler也只会处理自己发送的消息。
    即Handler:MessageQueue:Looper:Thread = N:1:1:1;
  • Q:为什么实际延迟消息处理时间比指定时间更长。
    A:有两个原因,一个延迟处理是通过SystemClock.uptimeMillis() 来计算的,此方法在系统休眠时并不会计时。还有一个原因是队列中的消息是要逐个处理的,当消息队列中消息过多时也造成延时。
  • Q:HandlerMessage的使用场景及禁止使用的场景
    在Android系统中出于性能优化考虑,Android的UI操作并不是线程安全的,这意味着如果有多个线程并发操作UI组件,可能导致线程安全问题。为了解决这个问题,Android制定了一条简单的原则,只允许UI线程(亦即主线程)修改Activity中的UI组件,否则会抛出异常,但是我们经常将耗时操作(DB、网络在子线程进行操作),这也就需要通过HandlerMessage机制将消息从子线程切换到主线程。总结就是:在子线程做完耗时的逻辑处理后 将消息或者结果发送到主线程用于更新UI,其他场景都不建议大家使用HandlerMessage机制。
    禁止的场景是:子线程发送Message消息对象到主线程处理,又将消息对象因为耗时或者其他原因切换子线程来进行处理。这种会导致多线程安全问题。因为我们现在建议的方法都是通过obtainMessage从消息池获取,在Looper.loop()方法中,方法处理方法dispatchMessage和消息回收方法msg.recycleUnchecked(),也就是说如果你在dispatchMessage方法中将Message对象传递到子线程处理时,Message对象有可能被回收了,导致多线程安全问题。

3.源码

源码我将部分dump 和日志打印删节后全部贴上来,用于备查

package android.os;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
import android.util.Log;
import android.util.Printer;

import java.lang.reflect.Modifier;

/**
 * Handler可以发送和处理{@link Message}对象,以及与线程的{@link MessageQueue} 关联的Runnable对象,
 * 每一个Hnadler 对象只能关联一个线程以及这个线程对应的Looper。当创建一个新的Handler,它将绑定到{@link Looper}。
 * Hanlder会将消息和Runnable对象传递到Looper中的消息队列,并且在Looper关联的线程中执行他们。
 * 即可以理解,Handler:Looper:Thread:MessageQueue=N:1:1:1
 *
 * Hnadler 有两个主要用途:1)调度Message和Runnable实现类对象在未来的某个时间点来执行。
 * 2)将耗时任务安排在其他线程执行而不是当前线程
 *
 * 当post或者send消息到Handler时,用户可以让消息当消息队列Ready后立马处理,也可以延迟指定时间或者绝对时间再处理。
 * 后面两次方法可以实现超时、或者其他基于计时的行为。
 *
 * 当应用的进程被创建后,主线程专用于一个Message queue,负责管理顶级应用对象(activities, broadcast receivers, etc)
 * 和创建的窗口。用户可以创建自己的子线程,然后通过Handler和主线程进行通信,实现方法是在子线程中调用post 或者sendMessage等方法,
 * 被传入的Runnable实现类对象和Message对象会被排入Handler中的Message Queue,然后在适当的时候进行处理
 */
public class Handler {
    @UnsupportedAppUsage
    final Looper mLooper;
    final MessageQueue mQueue;
    @UnsupportedAppUsage
    final Callback mCallback;
    final boolean mAsynchronous;
    @UnsupportedAppUsage
    IMessenger mMessenger;
    /*
     * 当此标志设备为true,以检测非静态的匿名内部类(继承于Handler),这种类可能会产生内存泄漏
     */
    private static final boolean FIND_POTENTIAL_LEAKS = false;
    private static final String TAG = "Handler";
    private static Handler MAIN_THREAD_HANDLER = null;

    /**
     * Callback interface you can use when instantiating a Handler to avoid
     * having to implement your own subclass of Handler.
     * 回调接口,用于实例化Handler避免不得不实现自己的Handler子类
     */
    public interface Callback {
        /**
         * @param msg A {@link android.os.Message Message} object
         * @return 如果不需要进一步处理,则为true
         */
        boolean handleMessage(@NonNull Message msg);
    }

    /**
     * 子类必须实现他用于接收消息
     */
    public void handleMessage(@NonNull Message msg) {
    }

    /**
     * 处理系统消息,在Looper.loop(),当发现有消息时,会调用消息的目标Handler,执行此方法来分发消息
     */
    public void dispatchMessage(@NonNull Message msg) {
        if (msg.callback != null) {
            // 当Message存在回调方法时,回调msg.callback.run()方法
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                // 当Handler存在callback成员变量时,回调callback的handleMessage方法
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            // 执行Handler自身的回调方法handleMessage
            handleMessage(msg);
        }
    }

    /**
     * 默认构建方法,将当前线程的{@link Looper} 与此Handler对象进行关联
     *
     * 如果当前线程没有Looper,此Handler没有办法去接收消息,所以会抛出Exception
     *
     * @deprecated 在构建Handler时隐式指定Looper会导致一些错误,当Handler关联的线程不是用户想要的。比如:operations丢失(如果Hnadler没有接收新任务并退出),
     * Crashes(如果Handler不小心在构建时关联了一个没有Active Looper对象的线程),或者race Condition
     * 相反地,使用{@link java.util.concurrent.Executor},或者通过
     * {@link Looper#getMainLooper}, {link android.view.View#getHandler}或者类似的方法 显式指定Looper,
     * 为了兼容当前线程的隐式构建方法,使用{@code new Handler(Looper.myLooper())}
     *
     */
    @Deprecated
    public Handler() {
        this(null, false);
    }

    /**
     * Constructor associates this handler with the {@link Looper} for the
     * current thread and takes a callback interface in which you can handle
     * messages.
     * 构造方法将Handler 与当前线程的Looper进行关联,并指定一个可以处理消息的callback接口
     *
     * @param callback 用于处理消息的Callback接口,也可以为空
     **/

    @Deprecated
    public Handler(@Nullable Callback callback) {
        this(callback, false);
    }

    public Handler(@NonNull Looper looper) {
        this(looper, null, false);
    }

    public Handler(@NonNull Looper looper, @Nullable Callback callback) {
        this(looper, callback, false);
    }

    @UnsupportedAppUsage
    public Handler(boolean async) {
        this(null, async);
    }

    /**
     * 指定Looper为当前线程的Looper且为设置此Handler是否为异步,以及指定一个处理消息Callback接口
     *
     * 默认情况下,Handler是同步的,除非使用该构造函数指定为异步的
     *
     * 异步消息表示不需要相对于同步消息进行全局排序的中断或事件。
     * 异步消息不受{@link MessageQueue#enqueueSyncBarrier(long)引入的同步barriers的影响。
     *
     * @param callback 用于处理消息的callback接口实现类,也可为空
     * @param async 如果为true,则handler会
     * 对于每一个他分发的Message对象或者Runnable实现类都调用调用{@link Message#setAsynchronous(boolean)}
     *
     * @hide
     */
    public Handler(@Nullable Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> klass = getClass();
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                    (klass.getModifiers() & Modifier.STATIC) == 0) {
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                        klass.getCanonicalName());
            }
        }

        mLooper = Looper.myLooper();
        if (mLooper == null) {
            // 也即意味着在调用Handler方法前,必要调用先调用Looper.prepare()
            throw new RuntimeException(
                    "Can't create handler inside thread " + Thread.currentThread()
                            + " that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

    /**
     *
     * @param looper The looper, 不允许为空
     * @param callback 用于处理消息的callback接口实现类,也可为空
     * @param async 如果为true,则handler会
     * 对于每一个他分发的Message对象或者Runnable实现类都调用调用{@link Message#setAsynchronous(boolean)}
     *
     * @hide
     */
    @UnsupportedAppUsage
    public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

    @NonNull
    public static Handler createAsync(@NonNull Looper looper) {
        if (looper == null) throw new NullPointerException("looper must not be null");
        return new Handler(looper, null, true);
    }

    /**
     * 创建一个新的Handler,posted 的消息和Runnables对象不受同步barriers的约束,例如display vsync
     *
     * <p>Messages sent to an async handler are guaranteed to be ordered with respect to one another,
     * but not necessarily with respect to messages from other Handlers.</p>
     *
     * @see #createAsync(Looper) to create an async Handler without custom message handling.
     *
     * @param looper the Looper that the new Handler should be bound to
     * @return a new async Handler instance
     */
    @NonNull
    public static Handler createAsync(@NonNull Looper looper, @NonNull Callback callback) {
        if (looper == null) throw new NullPointerException("looper must not be null");
        if (callback == null) throw new NullPointerException("callback must not be null");
        return new Handler(looper, callback, true);
    }

    /** @hide */
    @UnsupportedAppUsage
    @NonNull
    public static Handler getMain() {
        if (MAIN_THREAD_HANDLER == null) {
            MAIN_THREAD_HANDLER = new Handler(Looper.getMainLooper());
        }
        return MAIN_THREAD_HANDLER;
    }

    /** @hide */
    @NonNull
    public static Handler mainIfNull(@Nullable Handler handler) {
        return handler == null ? getMain() : handler;
    }

    /**
     * 返回一个表示指定消息名称的字符串。默认实现要么返回* message回调的类名(如果有的话),要么返回* message“what”字段的十六进制表示。
     *
     * @param message 需要查询名称的消息对象
     */
    @NonNull
    public String getMessageName(@NonNull Message message) {
        if (message.callback != null) {
            return message.callback.getClass().getName();
        }
        return "0x" + Integer.toHexString(message.what);
    }

    /**
     * 从消息池中返回一个新的Message对象 {@link android.os.Message Message} .
     * 创建的消息会将此Handler设置为此实例(Message.target == this).
     *  也可以通过Message.obtain()来代替
     */
    @NonNull
    public final Message obtainMessage()
    {
        return Message.obtain(this);
    }

    @NonNull
    public final Message obtainMessage(int what)
    {
        return Message.obtain(this, what);
    }

    @NonNull
    public final Message obtainMessage(int what, @Nullable Object obj) {
        return Message.obtain(this, what, obj);
    }

    @NonNull
    public final Message obtainMessage(int what, int arg1, int arg2)
    {
        return Message.obtain(this, what, arg1, arg2);
    }

    @NonNull
    public final Message obtainMessage(int what, int arg1, int arg2, @Nullable Object obj) {
        return Message.obtain(this, what, arg1, arg2, obj);
    }

    /**
     * 将Runnable实现类添加到消息对队中,Runnable实现类在在Handler关联的线程中执行。
     *
     * @param r The Runnable that will be executed.
     * @return 当Runnable实现类对象r成功添加到消息队列中返回true,失败时则返回false,通常是因为处理消息队列的Looper不存在
     */
    public final boolean post(@NonNull Runnable r) {
        return  sendMessageDelayed(getPostMessage(r), 0);
    }

    /**
     * 将Runnable实现类添加到消息对队中,其将会在uptimeMillis指定的特定时间执行,手机休眠会增加执行的额外延迟,
     * Runnable实现类在在Handler关联的线程中执行。
     *
     * @param r The Runnable that will be executed.
     * @param uptimeMillis 回调执行的绝对时间,(并非相对时间),使用{@link android.os.SystemClock#uptimeMillis}作为基础时间
     */
    public final boolean postAtTime(@NonNull Runnable r, long uptimeMillis) {
        return sendMessageAtTime(getPostMessage(r), uptimeMillis);
    }

    /**
     * Causes the Runnable r to be added to the message queue, to be run
     * at a specific time given by <var>uptimeMillis</var>.
     * 将Runnable实现类添加到消息对队中,其将会在uptimeMillis指定的特定时间执行,手机休眠会增加执行的额外延迟,
     * Runnable实现类在在Handler关联的线程中执行。
     *
     * @param r The Runnable that will be executed.
     * @param token 可以通过此Token 通过{@link #removeCallbacksAndMessages}取消{@code r}的实例
     * @param uptimeMillis 回调执行的绝对时间,(并非相对时间),使用{@link android.os.SystemClock#uptimeMillis}作为基础时间
     *
     * @return 当Runnable实现类对象r成功添加到消息队列中返回true,失败时则返回false,通常是因为处理消息队列的Looper不存在
     * 注意:返回true并不代表Runnable会被执行,比如如果Looper被quit()在消息被分发时,会导致队列中的所有消息都被丢弃
     *
     * @see android.os.SystemClock#uptimeMillis
     */
    public final boolean postAtTime(
            @NonNull Runnable r, @Nullable Object token, long uptimeMillis) {
        return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);
    }

    public final boolean postDelayed(@NonNull Runnable r, long delayMillis) {
        return sendMessageDelayed(getPostMessage(r), delayMillis);
    }

    /** @hide */
    public final boolean postDelayed(Runnable r, int what, long delayMillis) {
        return sendMessageDelayed(getPostMessage(r).setWhat(what), delayMillis);
    }

    public final boolean postDelayed(
            @NonNull Runnable r, @Nullable Object token, long delayMillis) {
        return sendMessageDelayed(getPostMessage(r, token), delayMillis);
    }

    /**
     * 将发送一个Runnable实现类到队列队首,消息将在下一次循环时首先执行
     * 此方法仅用于非常特殊的情况下使用,它会带来排序问题以及其他副作用
     **/
    public final boolean postAtFrontOfQueue(@NonNull Runnable r) {
        return sendMessageAtFrontOfQueue(getPostMessage(r));
    }

    /**
     * 同步运行指定的任务(同步方法)(危险方法)
     * <p>
     * 如果当前线程是Handler关联线程,则Runnable会立马执行,否则会将Runnables 发送至Handlersr执行且等他执行完成
     **/
    public final boolean runWithScissors(@NonNull Runnable r, long timeout) {
        if (r == null) {
            throw new IllegalArgumentException("runnable must not be null");
        }
        if (timeout < 0) {
            throw new IllegalArgumentException("timeout must be non-negative");
        }

        if (Looper.myLooper() == mLooper) {
            r.run();
            return true;
        }

        BlockingRunnable br = new BlockingRunnable(r);
        return br.postAndWait(this, timeout);
    }

    /**
     * 删除所有消息队列中待等待执行的Runnable实现类对象
     */
    public final void removeCallbacks(@NonNull Runnable r) {
        mQueue.removeMessages(this, r, null);
    }

    /**
     * 删除所有带有token的等待执行的Runnable实现类对象,如果token为null,则所有的callbacks将会被删除
     */
    public final void removeCallbacks(@NonNull Runnable r, @Nullable Object token) {
        mQueue.removeMessages(this, r, token);
    }

    public final boolean sendMessage(@NonNull Message msg) {
        return sendMessageDelayed(msg, 0);
    }

    public final boolean sendEmptyMessage(int what)
    {
        return sendEmptyMessageDelayed(what, 0);
    }

    public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
        Message msg = Message.obtain();
        msg.what = what;
        return sendMessageDelayed(msg, delayMillis);
    }

    public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
        Message msg = Message.obtain();
        msg.what = what;
        return sendMessageAtTime(msg, uptimeMillis);
    }

    /**
     * 发送一个延迟delayMillis ms的消息到队列中
     **/
    public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }

    /**
     * 在绝对时间uptimeMillis ms时将一个消息对象添加到消息队列队列中,(注意是绝对时间)
     * 基础时间是指调用时的{@link android.os.SystemClock#uptimeMillis}.如果手机进入休眠状态,将会增加额外的时间延迟。
     *
     * @param uptimeMillis 消息应该投递至消息队列中的绝对时间,使用{@link android.os.SystemClock#uptimeMillis}作为基础时间
     * @return 当Runnable实现类对象r成功添加到消息队列中返回true, 失败时则返回false, 通常是因为处理消息队列的Looper不存在
     *      * 注意:返回true并不代表Runnable会被执行,比如如果Looper被quit()在消息被分发时,会导致队列中的所有消息都被丢弃
     */
    public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue;
        if (queue == null) {
            RuntimeException e = new RuntimeException(
                    this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
            return false;
        }
        return enqueueMessage(queue, msg, uptimeMillis);
    }

    /**
     * 将发送一个Runnable实现类到队列队首,消息将在下一次循环时首先执行
     * 此方法仅用于非常特殊的情况下使用,它会带来排序问题以及其他副作用
     **/
    public final boolean sendMessageAtFrontOfQueue(@NonNull Message msg) {
        MessageQueue queue = mQueue;
        if (queue == null) {
            RuntimeException e = new RuntimeException(
                    this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
            return false;
        }
        return enqueueMessage(queue, msg, 0);
    }

    /**
     * 如果此方法在Looper的同一线程中调用,则同步执行消息,否则则调用{@link #sendMessage}将消息投递到消息队列中
     *
     * @hide 不对外开放,无法通过SDK调用
     */
    public final boolean executeOrSendMessage(@NonNull Message msg) {
        if (mLooper == Looper.myLooper()) {
            dispatchMessage(msg);
            return true;
        }
        return sendMessage(msg);
    }

    private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
                                   long uptimeMillis) {
        msg.target = this;
        msg.workSourceUid = ThreadLocalWorkSource.getUid();

        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

    /**
     * 将所有what与传入值一致的未分发消息从消息队列中删除
     */
    public final void removeMessages(int what) {
        mQueue.removeMessages(this, what, null);
    }

    /**
     * 删除消息队列中what等于传入值,且obj值等于传入的object值的消息。如果object等于null,则所有的消息都会被删除
     */
    public final void removeMessages(int what, @Nullable Object object) {
        mQueue.removeMessages(this, what, object);
    }

    /**
     *@hide
     */
    public final void removeEqualMessages(int what, @Nullable Object object) {
        mQueue.removeEqualMessages(this, what, object);
    }

    /**
     * Remove any pending posts of callbacks and sent messages whose
     * <var>obj</var> is <var>token</var>.  If <var>token</var> is null,
     * all callbacks and messages will be removed.
     */
    public final void removeCallbacksAndMessages(@Nullable Object token) {
        mQueue.removeCallbacksAndMessages(this, token);
    }

    /**
     *@hide
     */
    public final void removeCallbacksAndEqualMessages(@Nullable Object token) {
        mQueue.removeCallbacksAndEqualMessages(this, token);
    }
    /**
     * Check if there are any pending posts of messages with code 'what' in
     * the message queue.
     */
    public final boolean hasMessages(int what) {
        return mQueue.hasMessages(this, what, null);
    }

    /**
     * Return whether there are any messages or callbacks currently scheduled on this handler.
     * @hide
     */
    public final boolean hasMessagesOrCallbacks() {
        return mQueue.hasMessages(this);
    }

    /**
     * 判断消息队列中是否有未处理的what值和Obj值与传入的形参一致的
     */
    public final boolean hasMessages(int what, @Nullable Object object) {
        return mQueue.hasMessages(this, what, object);
    }

    /**
     *@hide
     */
    public final boolean hasEqualMessages(int what, @Nullable Object object) {
        return mQueue.hasEqualMessages(this, what, object);
    }

    /**
     * Check if there are any pending posts of messages with callback r in
     * the message queue.
     */
    public final boolean hasCallbacks(@NonNull Runnable r) {
        return mQueue.hasMessages(this, r, null);
    }

    // if we can get rid of this method, the handler need not remember its loop
    // we could instead export a getMessageQueue() method...
    @NonNull
    public final Looper getLooper() {
        return mLooper;
    }

    @Override
    public String toString() {
        return "Handler (" + getClass().getName() + ") {"
                + Integer.toHexString(System.identityHashCode(this))
                + "}";
    }

    @UnsupportedAppUsage
    final IMessenger getIMessenger() {
        synchronized (mQueue) {
            if (mMessenger != null) {
                return mMessenger;
            }
            mMessenger = new MessengerImpl();
            return mMessenger;
        }
    }

    private final class MessengerImpl extends IMessenger.Stub {
        public void send(Message msg) {
            msg.sendingUid = Binder.getCallingUid();
            Handler.this.sendMessage(msg);
        }
    }

    private static Message getPostMessage(Runnable r) {
        Message m = Message.obtain();
        m.callback = r;
        return m;
    }

    //  构建Message对象
    @UnsupportedAppUsage
    private static Message getPostMessage(Runnable r, Object token) {
        Message m = Message.obtain();
        m.obj = token;
        m.callback = r;
        return m;
    }

    private static void handleCallback(Message message) {
        message.callback.run();
    }

    private static final class BlockingRunnable implements Runnable {
        private final Runnable mTask;
        private boolean mDone;

        public BlockingRunnable(Runnable task) {
            mTask = task;
        }

        @Override
        public void run() {
            try {
                mTask.run();
            } finally {
                synchronized (this) {
                    mDone = true;
                    notifyAll();
                }
            }
        }

        public boolean postAndWait(Handler handler, long timeout) {
            if (!handler.post(this)) {
                return false;
            }

            synchronized (this) {
                if (timeout > 0) {
                    final long expirationTime = SystemClock.uptimeMillis() + timeout;
                    while (!mDone) {
                        long delay = expirationTime - SystemClock.uptimeMillis();
                        if (delay <= 0) {
                            return false; // timeout
                        }
                        try {
                            wait(delay);
                        } catch (InterruptedException ex) {
                        }
                    }
                } else {
                    while (!mDone) {
                        try {
                            wait();
                        } catch (InterruptedException ex) {
                        }
                    }
                }
            }
            return true;
        }
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值