V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
maninfog
V2EX  ›  Android

EventBus 源码关于 BackgroundPoster 的疑惑

  •  
  •   maninfog · 2019-08-04 14:57:43 +08:00 · 9325 次点击
    这是一个创建于 1964 天前的主题,其中的信息可能已经有所发展或是发生改变。

    源码如下:

     final class BackgroundPoster implements Runnable, Poster {
    
        private final PendingPostQueue queue;
        private final EventBus eventBus;
    
        private volatile boolean executorRunning;
    
        BackgroundPoster(EventBus eventBus) {
            this.eventBus = eventBus;
            queue = new PendingPostQueue();
        }
    
        public void enqueue(Subscription subscription, Object event) {
            PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
            synchronized (this) {
                queue.enqueue(pendingPost);
                if (!executorRunning) {
                    executorRunning = true;
                    eventBus.getExecutorService().execute(this);
                }
            }
        }
    
        @Override
        public void run() {
            try {
                try {
                    while (true) {
                        PendingPost pendingPost = queue.poll(1000);
                        if (pendingPost == null) {
                            synchronized (this) {
                                // Check again, this time in synchronized
                                pendingPost = queue.poll();
                                if (pendingPost == null) {
                                    executorRunning = false;
                                    return;
                                }
                            }
                        }
                        eventBus.invokeSubscriber(pendingPost);
                    }
                } catch (InterruptedException e) {
                    eventBus.getLogger().log(Level.WARNING, Thread.currentThread().getName() + " was interruppted", e);
                }
            } finally {
                executorRunning = false;
            }
        }
    
    
    

    从源码我得知BackgroundPoster从线程池中抽取了一个单独线程,循环读取队列中的PendingPost执行。那么但是既然是单线程,run()方法中的加锁的目的在哪里呢?我感觉完全可以去除加锁代码,简写成如下的代码:

    public void run() {
            try {
                try {
                    while (true) {
                        PendingPost pendingPost = queue.poll(1000);
                        if (pendingPost == null) {
                                    executorRunning = false;
                                    return;
                            }
                        }
                        eventBus.invokeSubscriber(pendingPost);
                    }
                } catch (InterruptedException e) {
                    eventBus.getLogger().log(Level.WARNING, Thread.currentThread().getName() + " was interruppted", e);
                }
            } finally {
                executorRunning = false;
            }
        }
    

    我是在哪方面没有考虑到呢?

    4 条回复    2019-08-05 11:06:05 +08:00
    shily
        1
    shily  
       2019-08-05 10:08:11 +08:00 via Android
    enqueue 方法是其他线程调用的啊,大兄弟。
    ChenFanlin
        2
    ChenFanlin  
       2019-08-05 10:49:21 +08:00   ❤️ 1
    EventBusBuilder#DEFAULT_EXECUTOR_SERVICE 是 Executors.newCachedThreadPool();
    然后这个 BackgroundPoster 是加了个变量`executorRunning`来使他同时只在一个线程中运行,两个锁是确保`executorRunning`的值不出错,两个加锁的代码块同时只能执行一个
    假如去掉了下面一个, 假设一种情况, 如果队列里是空的, 先执行`pendingPost = queue.poll();` 取到 null, **executorRunning 还未赋值为 false 的时候** , 这时候`queue.enqueue()`进去了,
    ```java
    if (!executorRunning) {
    executorRunning = true;
    eventBus.getExecutorService().execute(this);
    }
    ```
    这段代码就不会执行, 就得被推迟到下一次 background 的分发了
    **一只小菜鸡, 请轻喷**
    ChenFanlin
        3
    ChenFanlin  
       2019-08-05 10:53:56 +08:00
    ..原来回复不支持 md 啊..
    maninfog
        4
    maninfog  
    OP
       2019-08-05 11:06:05 +08:00
    @ChenFanlin #3 自己研究了下加上你的解释明白啦 感谢
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3209 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 20ms · UTC 12:41 · PVG 20:41 · LAX 04:41 · JFK 07:41
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.