专栏首页青蛙要fly的专栏虐面试官系列Lifecyele篇 - (3)源码分析之注册 & 发送

虐面试官系列Lifecyele篇 - (3)源码分析之注册 & 发送

前言:

原谅我标题党??

Lifecycle系列:

虐面试官系列Lifecyele 篇 -(1)基础讲解

虐面试官系列Lifecyele篇 - (2)源码分析之 Event & State

虐面试官系列Lifecyele篇 - (3)源码分析之注册 & 发送

虐面试官系列Lifecyele篇 - (4)源码分析之响应

待完成:

虐面试官系列Lifecyele 篇 - (5)集成Lifecycle的几种方式的源码差别

又是很久很久没写文章了,最近打算写下Android的又一基础知识: Android 官方架构组件系列。打算把相关的知识点都整理写下,所以本系列的主体为Lifecycle.


正文

虐面试官系列Lifecyele 篇 -(1)基础讲解中,我们讲过三种集成Lifecycle方式,我们上面讲了三种集成方式,其实一个集成方式源码通了,其他都都类似,我们以第一种最最普通的集成方式来讲解(其他的后期有空再补充吧)。

1. 添加注册监听:

房东类具体实现:LifecycleRegistry类

我们再来看Lifecycle的其他的抽象函数的具体实现,我们使用的又恰好是LifecycleRegistry类,该类继承了Lifecycle,所以直接查看该类即可 (PS : 对于这个类,会有很长很长的相关代码介绍,因为这个类是核心,没耐心看的也可以跳过):

public class LifecycleRegistry extends Lifecycle {
    
    //'核心属性单个介绍:'
    
    //'加入的LifecycleObserver会被加入到这个Map队列中(Ps:这个数据结构是核心,也会详细讲解)'
    private FastSafeIterableMap<LifecycleObserver, ObserverWithState> mObserverMap =
            new FastSafeIterableMap<>();
            
    //'当前的State状态'        
    private State mState;
    
    //'当前正在添加的Observer的数量'
    private int mAddingObserverCounter = 0;
    //'可有理解为是否在进行队列同步State(Sync()方法)状态判断值'
    private boolean mHandlingEvent = false;
    //'是否有新的Event值通知进来'
    private boolean mNewEventOccurred = false;
    //'这个如果我们是Activity,就是就Activity的实例'
    private final WeakReference<LifecycleOwner> mLifecycleOwner;
    
    ......
    ......
    ......
    
    @Override
    public void addObserver(@NonNull LifecycleObserver observer) {
        
        //'我们知道刚开始LifecycleObserver的默认状态是INITIALIZED,
        但是假如当前整个LifecycleRegistry的当前状态是DESTROYED,
        那我们也就知道了其实已经回不到其他状态了,
        我们就业直接把新添加的LifecycleObserver也变成DESTROYED,后续很多逻辑也就走不通了
        (就好比Activity已经变成了onDestory了,也不可能在变成其他什么onCraete,onResume状态了,回不去了)'
        State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
        
        
        //'我们知道LifecycleObserver是个观察者,我们给队列的观察者发送通知本来没啥,
        直接List<LifecycleObserver> 这个队列都可以管理,收到通知,直接遍历队列发送就可以,
        但是假如我们现在直接发送ON_RESUME状态,但我们的LifecycleObserver的状态为INITIALIZED,
        我们可能希望观察者收到的是ON_CREATE,ON_START,ON_RESUME都能收到,所以我们必须知道当前LifecycleObserver的状态,
        然后根据它的状态,和需要改变的最终的状态值,然后一步步的变化过去,然后一步步的发送事件。
        所以我们需要知道当前LifecycleObserver的State状态,
        就只能再拿一个ObserverWithState类来包裹住State字段和LifecycleObserver'
        ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);
        
        //'这里我们可以看到使用的是putIfAbsent方法存入队列,这个putIfAbsent在讲解这个数据结构的时候我们会讲到,
        它不像一般的Map结构,会用新的值覆盖老的值,而是发现有老的值,就直接把已经存的老的值返回。
        所以如果我们把传入的LifecycleObserver在队列中找到了的话,
        就说明前面就添加过了,现在是重复添加,直接return返回。'
        ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);
        if (previous != null) {
            return;
        }
        
        
        //'因为使用了弱引用,所以要获取一下当前的LifecycleOwner不为null,不然后面的就都出问题'
        LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
        if (lifecycleOwner == null) {
            // it is null we should be destroyed. Fallback quickly
            return;
        }

        
        //'先看字面意思mAddingObserverCounnter :Adding - Observer - counter 正在添加的LifecycleObserver的数量,
        我们可以看到下面有个mAddingObserverCounnter++ ,然后最后整个addObserver()方法执行完了之后,
        又会运行mAddingObserverCounter--,所以正常流程是进来一个LifecycleObserver进来添加,
        我们会用这个mAddingObserverCounter加一,然后LifecycleObserver整个都被添加完了后,我们就减一,正常添加是没问题,
        但是假如正好并发添加多个观察者,这时候可能一个先进行++操作,但是还没有整个addObserver()方法走完,
        另外一个也进来添加了,然后这时候我们的mAddingObserverCounter就 !=0 了。'
        
        //'我们再来看mHandlingEvent参数,字面意思:Handle - Event 处理Event事件,默认为false,
        它会在sync()方法(PS:sync()可以理解为更新整个LifecycleObserver队列的State并且发送Event事件方法)置为true,然后sync()方法执行完了后置为false
        {
        mHandlingEvent = true;
        sync();
        mHandlingEvent = false;
        }
        所以这个参数我们可以理解为当前是否正好在处理传入的Event事件( PS:也就是 处理传入事件,更新队列,发送通知)
        '
        
        //'isReentrance字面意思: is - Reetrance 是否是重入,
        所以我们认为同时多个在添加Observer或者同时发送多个Event进来,都算是重入'
        boolean isReentrance = mAddingObserverCounter != 0 || mHandlingEvent;
        
        //'获取目标State值(也可以简单先初步理解为LifecycleRegistry的State的当前值),后面这里我们会具体讲解'
        State targetState = calculateTargetState(observer);
        
        //'开始前加一'
        mAddingObserverCounter++;
        
        //'当前的加入的观察者的State值,与目标值进行比较,
        因为我们刚加入的观察者,State被赋予了DESTROYED或者INITIALIZED
        (PS: 还记得我们前面讲的枚举的小知识点吗?就是枚举值的比较那个
        聚个例子:比如我们新加的观察者状态是INITIALIZED,也就是数值1,
        而目标State是CREATED,也就是2,所以我们的观察者状态就小于当前的目标State了'
        while ((statefulObserver.mState.compareTo(targetState) < 0
                && mObserverMap.contains(observer))) {
            
            //'字面意思就知道,改变观察者的状态前,先把它自身的状态存起来'
            pushParentState(statefulObserver.mState);
            
            //'dispatchEvent 分发Event,但是里面的具体的参数是根据当前的观察者的状态值的上一步Event(实现一步步提升,一步步分发)'
            statefulObserver.dispatchEvent(lifecycleOwner, upEvent(statefulObserver.mState));
            
            //'改变观察者的状态后,把原来存的状态给删除掉'
            popParentState();
            
            
            //'重新计算一次目标State值'
            // mState / subling may have been changed recalculate
            targetState = calculateTargetState(observer);
        }
        
        //'我们上面说了,如果没有重入,则更新整个队列(如果有重入,如果我更新一遍队列,同时还要再更新一遍,中间同时更新一个队列出问题不说,也是浪费资源)'
        if (!isReentrance) {
            // we do sync only on the top level.
            sync();
        }
        
        //'mAddingObserverCounter参数减一'
        mAddingObserverCounter--;
    }
}

2. 发送事件到观察者队列:

讲完了注册,我们来看下我们发送事件:

比如我们在我们的Activity的onResume中发送事件:

 @Override
protected void onResume() {
    super.onResume();
    
    //'1.直接发送State,告诉要跳到这个State状态'
    registry.markState(Lifecycle.State.CREATED);
    
    //'2.直接的是Event,然后跳到相应的Event对应的State状态'
    registry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
 
}
复制代码

然后我们的观察者就会收到这个通知了。

我们来看下发送的相关源码:

//'通过第一种方法'
public void markState(@NonNull State state) {
    //'直接移动到指定的State状态值'
    moveToState(state);
}

//'通过第二种方法'
public void handleLifecycleEvent(@NonNull Lifecycle.Event event) {
    //'通过getStateAfter方法来获取下一个State值(具体其实就是根据我们的State和Event的关系图)'
    State next = getStateAfter(event);
    //'然后直接移动到指定的State状态值'
    moveToState(next);
}

我们继续来看moveToState

private void moveToState(State next) {
    
    //'当前的State状态已经和要求变化的State一致,就没必要运行接下去的代码了
    (所以你发送多个相同State值,该方法只会执行一次)'
    if (mState == next) {
        return;
    }
    
    //'将当前的值改为要变化的值'
    mState = next;
    
    //'还记得这二个参数的意义不?? mHandlingEvent为true说明正在执行sync方法遍历观察者队列进行更新
    mAddingObserverCounter说明同时添加了多个观察者
    '
    if (mHandlingEvent || mAddingObserverCounter != 0) {
        
        //'如果进入是因为mHandlingEvent为true引起的,说明已经在更新队列,当前又有一个新的State发送进来,
        那么 1. 没必要去开启一个新的队列更新任务,所以这里会进行return
            2. 同时原来的队列更新任务如果正好更新到一半,那么已经更新好的那些观察者其实也已经不是最新的了,
            那么这个任务就要重新整个队列全部重新更新一遍,所以需要一个字段在sync()方法的更新队列里面告诉它有新的Event值进来了。
            没错,这个字段就是mNewEventOccurred,所以会有mNewEventOccurred  = true;
        '
        
        //'如果进入是因为mAddingObserverCounter进入,理由与上面类似(因为加入一个观察者后,我们也会执行sync,所以不需要再启动新的,同时用mNewEventOccureed字段告诉已经执行的sync()方法)'
        
        mNewEventOccurred  = true;
        return;
    }
    
    //如果有在执行sync操作,就把mHandlingEvent置为true
    mHandlingEvent = true;
    
    
    sync();
    
    
    //sync操作结束,置为false
    mHandlingEvent = false;
}

我们可以看到sync方法是比较重要的方法,因为起到了更新队列的功效,本来应该是直接看sync方法的源码,既然说了是更新队列,我们先来说下这个队列的数据结构基础知识,然后再回头看我们的sync方法源码,更容易理解。

3. 观察者队列数据结构FastSafeIterableMap分析:

PS: 这段实在没兴趣的读者,也可以不看.......

看之前如果对数据结构基础不是很了解,强烈建议看我以前

在这里我们既然讲到了注册时候会把新加入的LifecycleObserver加入到队列中,我们具体讲讲这个队列的数据结构:

我们先从字面意思来看,觉得它跟HashMap等数据结构一样,都是Map结尾,而且用法也差不多,都是put(key,value); get(key);

我们来看下HashMap的基础代码:

public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable {
    ......
}

可以看到HashMap实现了Map<K,V>接口,该接口定义了Map类型的相关方法定义,比如常见的put,get,containsKey,keySet等方法:

同时我们额外补充下HashMap的相关基础数据结构原理: 漫画:什么是HashMap? 漫画:高并发下的HashMap

我们再来看我们的FastSafeIterableMap类:

//'可以看名字就知道这个类只是一个(fast -  safeIterableMap),所以核心还是后面的SafeIterableMap类'
public class FastSafeIterableMap<K, V> extends SafeIterableMap<K, V> {
    
    ......
}


//'SafeIterableMap实现了Iterable接口'
public class SafeIterableMap<K, V> implements Iterable<Map.Entry<K, V>> {

    ......
}

我们可以看到,SafeIterableMap它并没有实现Map接口,倒是实现了Iterable接口,Iterable接口是不是感觉马上就有熟悉感了,什么??不知道是啥???

public interface Collection<E> extends Iterable<E> {

    ......
}

我们的Collection接口就是实现了该接口,Collection就更熟悉了:

PS: 具体Collection的介绍及相关实现类,可以具体看该文章:集合Collection总览,上面图片也引用该文章

这么一说就瞬间熟悉了,因为这个是链表结构的集合,那我们的SafeIterableMap是不是也是链表结构,答案是对的。

我们来根据代码一步步来看这个数据结构:

'比如我们的Lifecycle的addObserver方法:'
@Override
public void addObserver(@NonNull LifecycleObserver observer) {
    State initialState = mState == DESTROYED ? DESTROYED : INITIALIZED;
    ObserverWithState statefulObserver = new ObserverWithState(observer, initialState);
    
    //'使用了putIfAbsent方法'
    ObserverWithState previous = mObserverMap.putIfAbsent(observer, statefulObserver);

    ......
}

我们来看FastSafeIterableMap

public class FastSafeIterableMap<K, V> extends SafeIterableMap<K, V> {
    
    //'内部含有一个HashMap ,等等!不是说是链表吗?
    这个HashMap不是用来最后的存储队列的作用,
    我们知道链表的缺点是查找元素需要遍历链表来查找,非常耗时。
    而我们一些方法比如判断我们队列是否有某个值,或者取某个特定Key的值,如果遍历链表就太慢了
    我们就额外在数据添加到队列后,再添加到HashMap中,直接通过HashMap来判断是否有这个值或者获取值,就很快了'
    private HashMap<K, Entry<K, V>> mHashMap = new HashMap<>();
    
    
    //'HashMap额外进行辅助存储,来判断是否有该Key存储过'
    @Override
    protected Entry<K, V> get(K k) {
        return mHashMap.get(k);
    }


    //'这个方法是重点:'
    @Override
    public V putIfAbsent(@NonNull K key, @NonNull V v) {
    
        //'通过get方法,在内部这个HashMap中是否存过这个Key和Value'
        Entry<K, V> current = get(key);
        //如果取出来有值
        if (current != null) {
            //'直接把取出来的值返回,记住这个put重复的值进来,不会覆盖原来的值,只是把老的值返'
            return current.mValue;
        }
        
        //'如果没有存过,就内部这个HashMap把Key和Value存入,
        但是这个Value不是直接传入的Value,而是通过put()方法,先把这个内容,存到链表结构中,然后再放到HashMap中'
        mHashMap.put(key, put(key, v));
        return null;
    }

    @Override
    public V remove(@NonNull K key) {
        //'先从链表中把这个Key对应的值移除'
        V removed = super.remove(key);
        //'再在HashMap中把这个值移除'
        mHashMap.remove(key);
        return removed;
    }
    
    
    public boolean contains(K key) {
        //'通过HashMap来判断是否含有某个值'
        return mHashMap.containsKey(key);
    }

    public Map.Entry<K, V> ceil(K k) {
        
        //查看是否包含了这个Key对应的值
        if (contains(k)) {
            //'获取对应的值,然后取这个值的上一个值(这里可能会有疑惑,别急,后面就会解答)'
            return mHashMap.get(k).mPrevious;
        }
        return null;
    }
}

我们看到了,所谓的FastSafeIterableMapSafeIterableMap的区别是,内部多了一个额外HashMap,来帮助我们快速查找元素,从而不用遍历整个队列,节省了时间。

刚我们看到,我们在加入元素的时候:

mHashMap.put(key, put(key, v));

是通过put方法先加入到队列,然后加入到HashMap中,我们来看下put()方法:

protected Entry<K, V> put(@NonNull K key, @NonNull V v) {
    
    //我们new 了一个Entry对象,放入key和value
    Entry<K, V> newEntry = new Entry<>(key, v);
    
    //'因为是新加的,所以链表长度也加一'
    mSize++;
    
    //'链表结构大家都知道,是一条长的链,所以会有头有尾,
    如果最后一个是空的,说明现在这个链表里面没有元素,
    所以这个新加入的元素,既是头又是尾'
    if (mEnd == null) {
        mStart = newEntry;
        mEnd = mStart;
        return newEntry;
    }

    //'如果链表中已经有其他元素,则我们原本最后一个的元素就不是最后一个了,
    所以先让最后一个元素的下一个指向我们的新元素,然后我们的新元素的前一个指向了原来的最后一个元素,
    然后再把mEnd赋值成新的元素。''
    mEnd.mNext = newEntry;
    newEntry.mPrevious = mEnd;
    mEnd = newEntry;
    return newEntry;

}

没错,有些人可能会一脸懵逼,没关系,我已经为大家准备了图片,不怕大家不会。

首先我们知道Entry对象里面是怎么样的(其实就是Map里面我们经常看到的Entry对象):

static class Entry<K, V> implements Map.Entry<K, V> {
    
    //'Key 属性'
    final K mKey;
    //'Value属性'
    final V mValue;
    //'下一个Entry的属性'
    Entry<K, V> mNext;
    //'上一个Entry的属性'
    Entry<K, V> mPrevious;
    
    ......
    ......
    ......
}

换成图片就是这样:

然后这些Entry怎么连在一起呢?如下图所示这样:

是不是这样就一下子理解了。

所以我们刚在的添加Entry的相关代码就能理解了。

同时最近学了做动态动画,以后用来写博客就可以越来越顺手了,比如下图的链表删除元素(gif倒过来就是添加元素):

我们说了往数据结构添加了元素,我们再来说说遍历队列。 虽然我们的这个数据结构,没有直接继承Map,看我们看到它实现了迭代器,所以HashMap怎么遍历数据来着:

//获取迭代器
Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();

//判断迭代器是否有下一个元素值
while(it.hasNext()){
    //从迭代器中取出元素值
   Map.Entry<String, String> entry = it.next();
   System.out.println("key= "+entry.getKey()+" and value= "+entry.getValue());
}

所以我们的这个观察者队列,也是会有相关获取迭代器方法:

//'正序迭代器'
@NonNull
@Override
public Iterator<Map.Entry<K, V>> iterator() {
    ListIterator<K, V> iterator = new AscendingIterator<>(mStart, mEnd);
    mIterators.put(iterator, false);
    return iterator;
}

//'倒序迭代器'
public Iterator<Map.Entry<K, V>> descendingIterator() {
    DescendingIterator<K, V> iterator = new DescendingIterator<>(mEnd, mStart);
    mIterators.put(iterator, false);
    return iterator;
}

//'和上面二个最大的区别是,在迭代过程中,有新的元素被加进来,也可以遍历到'
public IteratorWithAdditions iteratorWithAdditions() {
    IteratorWithAdditions iterator = new IteratorWithAdditions();
    mIterators.put(iterator, false);
    return iterator;
}


复制代码

本来还想长篇的继续分析,但是后来看到其他博主有写的该数据结构很不错的文章:

Android 源码系列之【二十一】从源码的角度深入理解SafeIterableMap

所以配合我上面讲的基础,外加这篇文章,基本对该数据结构就能熟练掌握了。

4. sync()的具体流程:

我们具体来看更新队列的过程:

private void sync() {
    //'获取我们的被观察者是不是为空,如果为空,就直接返回了'
    LifecycleOwner lifecycleOwner = mLifecycleOwner.get();
    if (lifecycleOwner == null) {
        Log.w(LOG_TAG, "LifecycleOwner is garbage collected, you shouldn't try dispatch "
                + "new events from it.");
        return;
    }
    
    
    //'是否同步完成,看下面具体方法说明'
    while (!isSynced()) {
    
        mNewEventOccurred = false;
        
        //'当前实际的mState状态值比队列头的状态小,说明队列的状态值太大了,要后退变小
        ( 为什么比较队列头,后面会说明)'
        if (mState.compareTo(mObserverMap.eldest().getValue().mState) < 0) {
            
            //'进行后退操作'
            backwardPass(lifecycleOwner);
        }
        
        
        Entry<LifecycleObserver, ObserverWithState> newest = mObserverMap.newest();
        
        /**
        '
        mNewEventOccurred还是false,没有变为true,
        (如果是true了,说明有新的Event事件传入,那么这次更新也可以先结束了)
            &&
        当前实际的mState状态值比队列尾的状态大,说明队列的状态值太小了,要前进变大
        ( 为什么比较队列头,后面会说明)
        '    
        **/
        if (!mNewEventOccurred && newest != null
                && mState.compareTo(newest.getValue().mState) > 0) {
                
            //'进行前进操作'    
            forwardPass(lifecycleOwner);
        }
    }
    mNewEventOccurred = false;
}



//'判断是否同步完成方法:'
private boolean isSynced() {
    //'队列里面观察者数量为空,当然就认为同步完成,返回true'
    if (mObserverMap.size() == 0) {
        return true;
    }
    
    //'队列头的的观察者当前的State状态'
    State eldestObserverState = mObserverMap.eldest().getValue().mState;
    //'队列尾的的观察者当前的State状态'
    State newestObserverState = mObserverMap.newest().getValue().mState;
    
    /**
    '队列头与队列尾相同,说明整个队列都一致了'
        &&         
    '队列头与LifecycleRegistry的最新的State状态一样'
    ('说明整个队列里面的观察者状态都更新到了最新的State值,也就说明同步完成了')
    **/
    return eldestObserverState == newestObserverState && mState == newestObserverState;
}

复制代码

为什么我们都判断需要后退操作了,还需要重新去判断是否需要前进操作,而不是直接if(后退){xxxxxxx; return}????

我们为什么后退操作和前进操作时候拿队列里面的元素进行比较,二个比较的元素方向是相反的??

具体看前进操作和后退操作的具体源码(基本一样举一个源码即可):

private void backwardPass(LifecycleOwner lifecycleOwner) {
    Iterator<Entry<LifecycleObserver, ObserverWithState>> descendingIterator =
            mObserverMap.descendingIterator();
    
    //'因为我们的后退操作是从队列头开始,往队列尾更新的,
    所以迭代器是从头到尾的(前进操作则相反)'
    while (descendingIterator.hasNext() && !mNewEventOccurred) {
        Entry<LifecycleObserver, ObserverWithState> entry = descendingIterator.next();
        ObserverWithState observer = entry.getValue();
        while ((observer.mState.compareTo(mState) > 0 && !mNewEventOccurred
                && mObserverMap.contains(entry.getKey()))) {
            Event event = downEvent(observer.mState);
            pushParentState(getStateAfter(event));
            
            //'调用ObserverWithState的dispatchEvent方法进行事件分发'
            observer.dispatchEvent(lifecycleOwner, event);
            popParentState();
        }
    }
}
static class ObserverWithState {
    State mState;
    GenericLifecycleObserver mLifecycleObserver;

    ObserverWithState(LifecycleObserver observer, State initialState) {
        
        //'可以看到我们的Observer传入后,实际上通过Lifecycling.getCallback方法再次处理后返回了一个新的Observer'
        mLifecycleObserver = Lifecycling.getCallback(observer);
        mState = initialState;
    }
    
    
    void dispatchEvent(LifecycleOwner owner, Event event) {
        //'获取Event事件对应的State值'
        State newState = getStateAfter(event);
        //'与当前的最新的mState进行比较,取最小值'
        mState = min(mState, newState);
        //'调用具体的真正的观察者(或者是适配器观察者ApdaterObserver)的onStateChanged方法进行回调通知'
        mLifecycleObserver.onStateChanged(owner, event);
        mState = newState;
    }
}

到这里我们已经知道了,是调用了我们封装的ObserverWithState对象里面的mLifecycleObserveronStateChanged方法,而这个mLifecycleObserver是把我们addObserver时候传入的我们自己的Observer通过Lifecycling.getCallback方法再次处理后返回了一个新的Observer。说明我们传入的不同的Observer,返回的这个回调的mLifecycleObserver不同,下一篇我们会看到底有哪些不同的观察者。

结语

本文我们介绍了具体注册观察者和发送事件的相关源码。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 虐面试官系列Lifecyele篇 - (2)源码分析之 Event & State

    虐面试官系列Lifecyele篇 - (2)源码分析之 Event & State

    青蛙要fly
  • Android技能树 - Rxjava源码(1) 之 初步结构

    我们还是通过基础的例子来进行讲解,比如你有个快递,你很想知道快递是否已经到小区,你可能想要在快递刚到你的小区的时候就马上知道,然后马上就能享受拆快递所带来的乐趣...

    青蛙要fly
  • 项目需求讨论— ButterKnife初级小结

    在没有使用DataBinding之前,我的项目都是使用ButterKnife,当然对于ButterKnife大家估计都熟悉的不要太熟悉了。本文我也就当自己的一个...

    青蛙要fly
  • 应用消息中间件设计可以解决哪些实际问题?

    消息队列中间件是分布式系统中重要的组件,主要解决应用解耦,异步消息,流量削锋等问题,实现高性能,高可用,可伸缩和最终一致性架构。目前使用较多的消息队列有Acti...

    搜云库技术团队
  • Java消息队列总结只需一篇ActiveMQ、RabbitMQ、ZeroMQ、Kafka

    消息队列中间件是分布式系统中重要的组件,主要解决应用解耦,异步消息,流量削锋等问题,实现高性能,高可用,可伸缩和最终一致性架构。目前使用较多的消息队列有Acti...

    慕容千语
  • BlockingQueue队列

    阻塞队列 (BlockingQueue)是Java util.concurrent包下重要的数据结构,BlockingQueue提供了线程安全的...

    物流IT圈
  • MQ消息队列应用场景比较介绍

    消息队列中间件是分布式系统中重要的组件,主要解决应用解耦,异步消息,流量削锋等问题,实现高性能,高可用,可伸缩和最终一致性架构。目前使用较多的消息队列有Acti...

    搜云库技术团队
  • 你真的需要消息队列吗

    我是一个极简主义者,我不喜欢让软件过早或不必要地复杂化。向软件系统添加组件是增加复杂性的一种方法。让我们以消息团队为例。 消息队列是一个系统,使您能够获得容错、...

    企鹅号小编
  • JDK容器学习之Queue:LinkedBlockingQueue

    基于链表阻塞队列LinkedBlockingQueue 基于链表的无边界阻塞队列,常用与线程池创建中作为任务缓冲队列使用 I. 底层数据结构 先看一下内部定义...

    小灰灰
  • 消息队列kafka

    在流式计算中,Kafka一般用来缓存数据,Storm通过消费Kafka的数据进行计算。

    超蛋lhy

扫码关注云+社区

领取腾讯云代金券