EventBus源码解读详细注释(2)MainThread线程模型分析

[EventBus源码分析(一):入口函数提纲挈领(2.4版本)](http://blog.csdn.net/wangshihui512/article/details/51802172)
[EventBus源码分析(二):register方法保存事件的订阅者列表(2.4版本)](http://blog.csdn.net/wangshihui512/article/details/51819508)
[EventBus源码分析(三):post方法发布事件【获取事件的所有订阅者,反射调用订阅者事件处理方法】(2.4版本)](http://blog.csdn.net/wangshihui512/article/details/51821143)
[EventBus源码分析(四):线程模型分析(2.4版本)](http://blog.csdn.net/wangshihui512/article/details/51832001)
[EventBus源码解读详细注释(1)register的幕后黑手](http://blog.csdn.net/wangshihui512/article/details/50914817)
[EventBus源码解读详细注释(2)MainThread线程模型分析](http://blog.csdn.net/wangshihui512/article/details/50934012)
[EventBus源码解读详细注释(3)PostThread、MainThread、BackgroundThread、Async四种线程模式的区别](http://blog.csdn.net/wangshihui512/article/details/50935729)
[EventBus源码解读详细注释(4)register时刷新的两个map](http://blog.csdn.net/wangshihui512/article/details/50938663)
[EventBus源码解读详细注释(5)事件消息继承性分析 eventInheritance含义](http://blog.csdn.net/wangshihui512/article/details/50947102)
[EventBus源码解读详细注释(6)从事件发布到事件处理,究竟发生了什么!](http://blog.csdn.net/wangshihui512/article/details/50949960)


EventBus的线程模型

为何要定义线程模型?因为在Android的中线程的使用有以下的限制:
1 主线程不能被阻塞,UI的更新位于主线程,耗时操作如网络处理在后台线程 
2 事件的发送和处理可能会位于不同线程
通过使用EvenBus的线程模型,我们可以定义处理事件的线程模型。EventBus中有四种线程模型:PostThread,MainThread,BackgroundThread,Async,下面分别介绍之。 
PostThread 
默认的线程模型,事件发布和接收在相同的线程,适合用于完成时间非常短的任务,以免阻塞UI。例:
// Called in the same thread (default)
public void onEvent(MessageEvent event) {
    log(event.message);
}
MainThread 
订阅者的事件处理方法在主线程被调用,适合处理开销小的事件,以免阻塞主线程。例:
// Called in Android UI's main thread
public void onEventMainThread(MessageEvent event) {
    textField.setText(event.message);
}
BackgroundThread 
订阅者的事件处理在后台被调用。若事件发送线程位于主线程,EventBus将使用一个后台线程来逐个发送事件
// Called in the background thread
public void onEventBackgroundThread(MessageEvent event){
    saveToDisk(event.message);
}
Async 
事件处理位于一个单独的线程,该线程往往既不是发送事件的线程,也不是主线程。使用这个模型适用于事件发送无需等待事件处理后才返回,适合处理耗时操作,如请求网络。EventBus内部使用线程池来管理多个线程。例:
// Called in a separate thread
public void onEventAsync(MessageEvent event){
    backend.send(event.message);
}

接下来从源码的角度分析MainThread 

EventBus有个私有方法 postToSubscription,这个私有方法是如何调用的且听下回分解,先不管
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
    switch (subscription.subscriberMethod.threadMode) {
        case PostThread:
            invokeSubscriber(subscription, event);
            break;
        case MainThread:
            if (isMainThread) {
                invokeSubscriber(subscription, event);
            } else {
                mainThreadPoster.enqueue(subscription, event);
            }
            break;
通过解析线程模型,如果是MainThread线程模型,并且当前线程就是主线程,那么可以直接在当前主线程通过反射调用订阅者的事件处理方法;
如果当前线程不是主线程呢?当然只能借助Handler了,将此事件发送到主线程处理。
mainThreadPoster是EventBus的一个属性,类型为HandlerPoster
是这样构造的
mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
传入的第二个参数是主线程的Looper,第三个参数表示主线程事件处理最大时间为10ms,超时将重新调度事件
下边看下HandlerPoster的内部是干什么的 
final class HandlerPoster extends Handler {
    private final PendingPostQueue queue;
    /*事件处理最大时间,超时重新调度*/
    private final int maxMillisInsideHandleMessage;
    private final EventBus eventBus;
    private boolean handlerActive;

    HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage) {
        super(looper);
        this.eventBus = eventBus;
        this.maxMillisInsideHandleMessage = maxMillisInsideHandleMessage;
        queue = new PendingPostQueue();
    }
    /*入队列操作,传入订阅者和事件*/
    void enqueue(Subscription subscription, Object event) {
        /*将订阅者和事件封装成PendingPost*/
        PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
        synchronized (this) {
            queue.enqueue(pendingPost);
            if (!handlerActive) {
                handlerActive = true;
                /**   public final boolean sendMessage(Message msg)
                 * Pushes a message onto the end of the message queue after all pending messages
                 * before the current time. It will be received in handleMessage,
                 * in the thread attached to this handler.
                 * @return Returns true if the message was successfully placed in to the
                 *         message queue.  Returns false on failure, usually because the
                 *         looper processing the message queue is exiting.
                 */
                /**  public final Message obtainMessage()
                 * Returns a new  android.os.Message Messagefrom the global message pool. More efficient than
                 * creating and allocating new instances. The retrieved message has its handler set to this instance
                 * (Message.target == this).
                 */

                if (!sendMessage(obtainMessage())) {
                    throw new EventBusException("Could not send handler message");
                }
            }
        }
    }

    @Override
    public void handleMessage(Message msg) {
        boolean rescheduled = false;
        try {
            /**  native public static long uptimeMillis();
             * Returns milliseconds since boot, not counting time spent in deep sleep.
             * @return milliseconds of non-sleep uptime since boot.
             */
            /*记录循环开始的时间*/
            long started = SystemClock.uptimeMillis();
            /*死循环,从消息队列取出消息逐一处理*/
            while (true) {
                /*获取队首*/
                PendingPost pendingPost = queue.poll();
                /*如果队列为空*/
                if (pendingPost == null) {
                    synchronized (this) {
                        // Check again, this time in synchronized
                        pendingPost = queue.poll();
                        if (pendingPost == null) {
                            /*如果队里中没有消息需要处理,设置标志位,然后直接返回,退出循环*/
                            handlerActive = false;
                            return;
                        }
                    }
                }
                /*运用反射调用事件处理方法*/
                eventBus.invokeSubscriber(pendingPost);
                /*计算循环所用的时间*/
                long timeInMethod = SystemClock.uptimeMillis() - started;
                /*如果事件处理时间太长,超时,那么就重新调度*/
                if (timeInMethod >= maxMillisInsideHandleMessage) {
                    if (!sendMessage(obtainMessage())) {
                        throw new EventBusException("Could not send handler message");
                    }
                    rescheduled = true;
                    return;
                }
            }
        } finally {
            handlerActive = rescheduled;
        }
    }
}
这个类主要实现了一个在UI线程也就是主线程循环处理事件的功能,同时如果事件处理超时,将被重新调度。
顺便看下EventBus的数据结构是如何设计的
先看消息队列:
final class PendingPostQueue {
    private PendingPost head;
    private PendingPost tail;
    /*入队列操作*/
    synchronized void enqueue(PendingPost pendingPost) {
        /*良好编程习惯,入口参数检查*/
        if (pendingPost == null) {
            throw new NullPointerException("null cannot be enqueued");
        }
        /*尾部不是空指针,队列有尾部,后边加一个PendingPost数据,该数据指针域已初始化为空指针*/
        if (tail != null) {
            tail.next = pendingPost;
            tail = pendingPost;
            /*队列头部为空指针,那么肯定没有头部,也没有尾部,队列为空,把入队的新元素作为头部和尾部*/
        } else if (head == null) {
            head = tail = pendingPost;
            /*队列有头无尾抛出异常*/
        } else {
            throw new IllegalStateException("Head present, but no tail");
        }
        /**
         * Causes all threads which are waiting on this object's monitor (by means
         * of calling one of the code wait() methods) to be woken up. The threads
         * will not run immediately. The thread that called code notify() has to
         * release the object's monitor first. Also, the threads still have to
         * compete against other threads that try to synchronize on the same object.
         *This method can only be invoked by a thread which owns this object's
         * monitor. A thread becomes owner of an object's monitor
         * by executing a synchronized method of that object;
         * by executing the body of a code synchronized statement that synchronizes on the object;
         * by executing a synchronized static method if the object is of type code Class
         *  1)wait()、notify()和notifyAll()方法是本地方法,并且为final方法,无法被重写。
           2)调用某个对象的wait()方法能让当前线程阻塞,并且当前线程必须拥有此对象的monitor(即锁)
           3)调用某个对象的notify()方法能够唤醒一个正在等待这个对象的monitor的线程,
                如果有多个线程都在等待这个对象的monitor,则只能唤醒其中一个线程;
           4)调用notifyAll()方法能够唤醒所有正在等待这个对象的monitor的线程;

            调用某个对象的wait()方法,当前线程必须拥有这个对象的monitor(即锁),
            因此调用wait()方法必须在同步块或者同步方法中进行(synchronized块或者synchronized方法)
            调用某个对象的wait()方法,相当于让当前线程交出此对象的monitor,然后进入等待状态,
            等待后续再次获得此对象的锁(Thread类中的sleep方法使当前线程暂停执行一段时间,从而让其他线程有机会继续执行,但它并不释放对象锁);
           notify()方法能够唤醒一个正在等待该对象的monitor的线程,当有多个线程都在等待该对象的monitor的话,
            则只能唤醒其中一个线程,具体唤醒哪个线程则不得而知。
           同样地,调用某个对象的notify()方法,当前线程也必须拥有这个对象的monitor,
            因此调用notify()方法必须在同步块或者同步方法中进行(synchronized块或者synchronized方法)。
           nofityAll()方法能够唤醒所有正在等待该对象的monitor的线程,这一点与notify()方法是不同的。
           这里要注意一点:notify()和notifyAll()方法只是唤醒等待该对象的monitor的线程,并不决定哪个线程能够获取到monitor。
            一个线程被唤醒不代表立即获取了对象的monitor,只有等调用完notify()或者notifyAll()并退出synchronized块,
            释放对象锁后,其余线程才可获得锁执行。
         */
        notifyAll();
    }
    /*队首出队列*/
    synchronized PendingPost poll() {
        PendingPost pendingPost = head;
        if (head != null) {
            /*队首出队列,将原队列第二个数据作为新的队首*/
            /*注意原队列只有一个数据的情况,队首==队尾都不是null,现在若队首出队列,队尾应该设置null*/
            head = head.next;
            if (head == null) {
                tail = null;
            }
        }
        /*队列为空,返回空指针*/
        return pendingPost;
    }
    /*如果队列为空,挂起当前线程,知道有新的数据加入队列(入队列操作后调用了notifyall() )*/
    synchronized PendingPost poll(int maxMillisToWait) throws InterruptedException {
        if (head == null) {
            /**
             * Causes the calling thread to wait until another thread calls the
             * notify() or  notifyAll()method of this object or until the
             * specified timeout expires. This method can only be invoked by a thread
             * which owns this object's monitor;
             * While the thread waits, it gives up ownership of this object's
             * monitor. When it is notified (or interrupted), it re-acquires the monitor
             * before it starts running.
             * A timeout of zero means the calling thread should wait forever unless interrupted or
             * notified.
             * wait():
             等待对象的同步锁,需要获得该对象的同步锁才可以调用这个方法,
             否则编译可以通过,但运行时会收到一个异常:IllegalMonitorStateException。
             调用任意对象的 wait() 方法导致该线程阻塞,该线程不可继续执行,并且该对象上的锁被释放。
             notify():
             唤醒在等待该对象同步锁的线程(只唤醒一个,如果有多个在等待),注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,
             而是由JVM确定唤醒哪个线程,而且不是按优先级。
             调用任意对象的notify()方法则导致因调用该对象的 wait()方法而阻塞的线程中随机选择的一个解除阻塞(但要等到获得锁后才真正可执行)。
             notifyAll():
             唤醒所有等待的线程,注意唤醒的是notify之前wait的线程,对于notify之后的wait线程是没有效果的。
             */
            wait(maxMillisToWait);
        }
        /*获得对象锁后返回队首数据*/
        return poll();
    }
}

再看消息类:
final class PendingPost {
    /*开一个对象池,静态ArrayList实现*/
    private final static List<PendingPost> pendingPostPool = new ArrayList<PendingPost>();
    /*数据部分是事件和订阅者*/
    Object event;
    Subscription subscription;
    /*保持链表结构,指向下一个节点*/
    PendingPost next;
    /*私有构造函数,封装事件和订阅者*/
    private PendingPost(Object event, Subscription subscription) {
        this.event = event;
        this.subscription = subscription;
    }
    /*传入事件和订阅者,返回一个封装好的PendingPost*/
    static PendingPost obtainPendingPost(Subscription subscription, Object event) {
        /*对对象池加锁*/
        synchronized (pendingPostPool) {
            int size = pendingPostPool.size();
            /*如果对象池保存的有备胎对象,就用备胎对象,节省一次new对象*/
            if (size > 0) {
                /*从池子里边拿出来一个PendingPost*/
                /*   * Removes the object at the specified location from this code List.
                     * @param location   the index of the object to remove.
                     * @return the removed object.
                     * 从池子也就是list拿出来一个PendingPost*/
                PendingPost pendingPost = pendingPostPool.remove(size - 1);
                pendingPost.event = event;
                pendingPost.subscription = subscription;
                pendingPost.next = null;
                return pendingPost;
            }
        }
        /*对象池没有保存备胎对象,就只能新创建一个对象了*/
        return new PendingPost(event, subscription);
    }
    /*归还一个对象给对象池*/
    static void releasePendingPost(PendingPost pendingPost) {
        pendingPost.event = null;
        pendingPost.subscription = null;
        pendingPost.next = null;
        synchronized (pendingPostPool) {
            // Don't let the pool grow indefinitely
            if (pendingPostPool.size() < 10000) {
                pendingPostPool.add(pendingPost);
            }
        }
    }
}




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值