EventBus 소스 코드 분석

26289 단어
제목: EventBus 소스 코드 분석 날짜: 2017 - 09 - 15 09: 38: 14 태그: [Source Code] categories: android
보 이 는 디자인 모드:
  • 단일 모드
  • 구축 자 모드
  • 중개 모델 (EventBus 자신 이 중개자)
  • 대상 풀 모드 (pendingPostPool 지연 이벤트 풀)
  • 데이터 구조 지식:
  • 링크 구조 (PendingPost Queue 이벤트 큐)
  • EventBus.class
    생 성 방법 은 단일 모드 입 니 다.
    static volatile EventBus defaultInstance;
    
    /** Convenience singleton for apps using a process-wide EventBus instance. */
    public static EventBus getDefault() {
        if (defaultInstance == null) {
            synchronized (EventBus.class) {
                if (defaultInstance == null) {
                    defaultInstance = new EventBus();
                }
            }
        }
        return defaultInstance;
    }
    

    생 성 방법 은 빌 더 모드 를 사 용 했 습 니 다:
    //        
    public static EventBusBuilder builder() {
        return new EventBusBuilder();
    }
    
    //        ,           
    private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();
    public EventBus() {
        this(DEFAULT_BUILDER);
    }
    
    EventBus(EventBusBuilder builder) {
        subscriptionsByEventType = new HashMap<>();
        typesBySubscriber = new HashMap<>();
        stickyEvents = new ConcurrentHashMap<>();
        mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
        backgroundPoster = new BackgroundPoster(this);
        asyncPoster = new AsyncPoster(this);
        indexCount = builder.subscriberInfoIndexes != nulbuilder.subscriberInfoIndexes.size() : 0;
        subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
                builder.strictMethodVerification, builder.ignoreGeneratedIndex);
        logSubscriberExceptions = builder.logSubscriberExceptions;
        logNoSubscriberMessages = builder.logNoSubscriberMessages;
        sendSubscriberExceptionEvent = builder.sendSubscriberExceptionEvent;
        sendNoSubscriberEvent = builder.sendNoSubscriberEvent;
        throwSubscriberException = builder.throwSubscriberException;
        eventInheritance = builder.eventInheritance;
        executorService = builder.executorService;
    }
    

    몇 가지 중요 한 방법
    등록 수신 자 register
    /**
     * Registers the given subscriber to receive events. Subscribers must call {@l#unregister(Object)} once they
     * are no longer interested in receiving events.
     * 
     * Subscribers have event handling methods that must be annotated by {@link Subscribe}.
     * The {@link Subscribe} annotation also allows configuration like {@link
     * ThreadMode} and priority.
     */
    public void register(Object subscriber) {
        Class> subscriberClass = subscriber.getClass();
        List subscriberMethodsubscriberMethodFinder.findSubscriberMethods(subscriberClass);
        synchronized (this) {
            for (SubscriberMethod subscriberMethod : subscriberMethods) {
                subscribe(subscriber, subscriberMethod);
            }
        }
    }
    

    이벤트 수신 자 를 등록 합 니 다.
  • List subscriberMethodsubscriberMethodFinder.findSubscriberMethods(subscriberClass); 이 방법 으로 이벤트 수신 자 클래스 에서 정 의 된 이벤트 수신 방법 (@ Subscribe 주 해 를 사용 하 는 방법)
  • Subscriber Method: 수신 자 수신 방법 에 대한 패키지
  •     // Must be called in synchronized block
        private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
            Class> eventType = subscriberMethod.eventType;
            Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
            CopyOnWriteArrayList subscriptions = subscriptionsByEventType.get(eventType);
            if (subscriptions == null) {
                subscriptions = new CopyOnWriteArrayList<>();
                subscriptionsByEventType.put(eventType, subscriptions);
            } else {
                if (subscriptions.contains(newSubscription)) {
                    throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
                            + eventType);
                }
            }
    
            int size = subscriptions.size();
            for (int i = 0; i <= size; i++) {
                if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
                    subscriptions.add(i, newSubscription);
                    break;
                }
            }
    
            List> subscribedEvents = typesBySubscriber.get(subscriber);
            if (subscribedEvents == null) {
                subscribedEvents = new ArrayList<>();
                typesBySubscriber.put(subscriber, subscribedEvents);
            }
            subscribedEvents.add(eventType);
    
            if (subscriberMethod.sticky) {
                if (eventInheritance) {
                    // Existing sticky events of all subclasses of eventType have to be considered.
                    // Note: Iterating over all events may be inefficient with lots of sticky events,
                    // thus data structure should be changed to allow a more efficient lookup
                    // (e.g. an additional map storing sub classes of super classes: Class -> List).
                    Set, Object>> entries = stickyEvents.entrySet();
                    for (Map.Entry, Object> entry : entries) {
                        Class> candidateEventType = entry.getKey();
                        if (eventType.isAssignableFrom(candidateEventType)) {
                            Object stickyEvent = entry.getValue();
                            checkPostStickyEventToSubscription(newSubscription, stickyEvent);
                        }
                    }
                } else {
                    Object stickyEvent = stickyEvents.get(eventType);
                    checkPostStickyEventToSubscription(newSubscription, stickyEvent);
                }
            }
        }
    
  • Subscription: 이벤트 수신 자 (Object) 와 이벤트 수신 자 내부 이벤트 수신 방법 (Subscriber Method)
  • EventBus 구성원 변수: Map, CopyOnWriteArrayList> subscriptionsByEventType 이벤트 수신 자 와 관련 된 Subscription
  • 을 저장 합 니 다.
  • subscriptions ByEventType: 이벤트 수신 우선 순위 에 따라 Subscription 정렬
  • eventType: 사실은 이벤트. class
  • EventBus 구성원 변수: Map>> typesBySubscriber: key - 수신 자 대상 저장, value: eventType (이벤트. class)
  • sticky 사건 의 실현???

  • 등록 취소
        /** Unregisters the given subscriber from all event classes. */
        public synchronized void unregister(Object subscriber) {
            List> subscribedTypes = typesBySubscriber.get(subscriber);
            if (subscribedTypes != null) {
                for (Class> eventType : subscribedTypes) {
                    unsubscribeByEventType(subscriber, eventType);
                }
                typesBySubscriber.remove(subscriber);
            } else {
                Log.w(TAG, "Subscriber to unregister was not registered before: " + subscriber.getClass());
            }
        }
    
        /** Only updates subscriptionsByEventType, not typesBySubscriber! Caller must update typesBySubscriber. */
        private void unsubscribeByEventType(Object subscriber, Class> eventType) {
            List subscriptions = subscriptionsByEventType.get(eventType);
            if (subscriptions != null) {
                int size = subscriptions.size();
                for (int i = 0; i < size; i++) {
                    Subscription subscription = subscriptions.get(i);
                    if (subscription.subscriber == subscriber) {
                        subscription.active = false;
                        subscriptions.remove(i);
                        i--;
                        size--;
                    }
                }
            }
        }
    
  • 수신 자 에 대응 하 는 [event Type s]
  • [eventType s] 를 통 해 typesBySubscriber 에서 eventType - list 삭제
  • 수신 자 삭제 subscriptionsByEventType송신 이벤트
        /** Posts the given event to the event bus. */
        public void post(Object event) {
            PostingThreadState postingState = currentPostingThreadState.get();
            List eventQueue = postingState.eventQueue;
            eventQueue.add(event);
    
            if (!postingState.isPosting) {
                postingState.isMainThread = Looper.getMainLooper() == Looper.myLooper();
                postingState.isPosting = true;
                if (postingState.canceled) {
                    throw new EventBusException("Internal error. Abort state was not reset");
                }
                try {
                    while (!eventQueue.isEmpty()) {
                        postSingleEvent(eventQueue.remove(0), postingState);
                    }
                } finally {
                    postingState.isPosting = false;
                    postingState.isMainThread = false;
                }
            }
        }
    
  • EventBus 구성원 변수: typesBySubscriber
  • 이 방법 은 이 벤트 를 보 내 는 라인 을 기록 하 는 라인 상태 클래스 를 초기 화 합 니 다: PostingThreadState
  • 이벤트 발송 방법:
        private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
            Class> eventClass = event.getClass();
            boolean subscriptionFound = false;
            if (eventInheritance) {
                List> eventTypes = lookupAllEventTypes(eventClass);
                int countTypes = eventTypes.size();
                for (int h = 0; h < countTypes; h++) {
                    Class> clazz = eventTypes.get(h);
                    subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
                }
            } else {
                subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
            }
            if (!subscriptionFound) {
                if (logNoSubscriberMessages) {
                    Log.d(TAG, "No subscribers registered for event " + eventClass);
                }
                if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
                        eventClass != SubscriberExceptionEvent.class) {
                    post(new NoSubscriberEvent(this, event));
                }
            }
        }
    
  • ThreadLocal currentPostingThreadState 방법 은 이벤트 클래스 를 통 해 이벤트 Types (이벤트 클래스 집합)
  • 를 찾 습 니 다.
  • EventBus 구성원 변수 lookupAllEventTypes(Class> eventClass) 이벤트 클래스 - eventTypes 관련 실현
  • 이벤트 스 레 드 가 다 르 기 전에 코드 전환:
        private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
            switch (subscription.subscriberMethod.threadMode) {
                case POSTING:
                    invokeSubscriber(subscription, event);
                    break;
                case MAIN:
                    if (isMainThread) {
                        invokeSubscriber(subscription, event);
                    } else {
                        mainThreadPoster.enqueue(subscription, event);
                    }
                    break;
                case BACKGROUND:
                    if (isMainThread) {
                        backgroundPoster.enqueue(subscription, event);
                    } else {
                        invokeSubscriber(subscription, event);
                    }
                    break;
                case ASYNC:
                    asyncPoster.enqueue(subscription, event);
                    break;
                default:
                    throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
            }
        }
    

    이벤트 큐
    EventBus 구성원 변수:
    private final HandlerPoster mainThreadPoster;
    private final BackgroundPoster backgroundPoster;
    private final AsyncPoster asyncPoster;
    
  • mainThreadPoster: 메 인 스 레 드 에서 실행 해 야 할 모든 이 벤트 를 저장 합 니 다.
  • backgroundPoster: 하위 스 레 드 에서 실행 해 야 할 모든 이 벤트 를 저장 합 니 다.(ExecutorService 를 사용 하여 하위 스 레 드 를 가 져 와 실행 하고 BackgroundPoster 는 Runnable 인 터 페 이 스 를 실현 합 니 다)
  • asyncPoster: 하위 스 레 드 에서 실행 해 야 할 모든 이 벤트 를 저장 합 니 다 (ExecutorService 를 사용 하여 하위 스 레 드 를 가 져 온 후 실행 합 니 다. AsyncPoster 는 Runnable 인 터 페 이 스 를 실현 합 니 다)
  • BackgroundPoster vs AsyncPoster
    구별
  • 이벤트 대기 열 에서 이 벤트 를 가 져 올 때: BackgroundPoster 는 지연 이벤트 (1000) 를 사용 하고 AsyncPoster 는 즉시 이벤트
  • 를 가 져 옵 니 다.
    HandlerPoster.class
    구조 방법
    Handler 의 하위 클래스 입 니 다. EventBus 에서 만 듭 니 다. 만 들 때 mainLopper 로 만 듭 니 다.
    mainThreadPoster = new HandlerPoster(this, Looper.getMainLooper(), 10);
    
    //...
    HandlerPoster(EventBus eventBus, Looper looper, int maxMillisInsideHandleMessage)
    
    

    구성원 변수
        private final PendingPostQueue queue;
        private final int maxMillisInsideHandleMessage;
        private final EventBus eventBus;
        private boolean handlerActive;
    
  • quue: 주 스 레 드 에서 실행 해 야 할 이벤트 대기 열
  • eventBus: EventBus 대상
  • handlerActive: 이벤트 가 실행 중인 지 기록 하기
  • maxMillisInside HandleMessage: 시간 초과 기록
  • 대기 열 에 이벤트 추가
        void enqueue(Subscription subscription, Object event) {
            PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
            synchronized (this) {
                queue.enqueue(pendingPost);
                if (!handlerActive) {
                    handlerActive = true;
                    if (!sendMessage(obtainMessage())) {
                        throw new EventBusException("Could not send handler message");
                    }
                }
            }
        }
    
  • Subscription (이벤트 수신 자 Object 와 이벤트 수신 자 내부 이벤트 처리 방법 SubscriberMethod 의 패키지) 을 통 해 PendingPost (지연 이벤트)
  • 를 만 듭 니 다.
  • handlerActive: true 를 위해 이벤트 대기 열의 처리 메커니즘 이 시작 되 었 음 을 표시 합 니 다. (이 메커니즘 은 이벤트 대기 열 queue 의 모든 이벤트 가 처 리 된 후에 정 지 됩 니 다) false 를 위해 현재 이벤트 처리 메커니즘 이 정 지 된 상 태 를 표시 합 니 다.
  • Map, List>> eventTypesCache: 대기 열 에 지연 이벤트 추가
  • queue.enqueue(pendingPost);: 이벤트 처리 메커니즘 시작
  • handleMessage
        @Override
        public void handleMessage(Message msg) {
            boolean rescheduled = false;
            try {
                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;
            }
        }
    
  • max MillisInside HandleMessage: 내부 정의 10
  • rescheduled: 이번 순환 으로 하나의 사건 을 처리 했다 고 밝 혔 다
  • BackgroundPoster.class
    런 나 블 인터페이스
    구성원 변수
        private final PendingPostQueue queue;
        private final EventBus eventBus;
    
        private volatile boolean executorRunning;
    
  • queue: 이벤트 대기 열
  • EventBus
  • executor Running: 이벤트 처리 메커니즘 (하나의 순환) 이 실행 중인 지 여부
  • 이벤트 추가
        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);
                }
            }
        }
    

    마찬가지 로 Subscription + event = PendingPost (이벤트 관련 정 보 를 패키지 하여 이벤트 대기 열 에 넣 어 처리)
    이벤트 추가 후 이벤트 처리 메커니즘 시작
    이벤트 처리 메커니즘 (사순환)
        @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) {
                    Log.w("Event", Thread.currentThread().getName() + " was interruppted", e);
                }
            } finally {
                executorRunning = false;
            }
        }
    
  • sendMessage(obtainMessage()): 1s 지연 대기 열 에서 이벤트 추출
  • AsyncPoster.class
    class AsyncPoster implements Runnable {
    
        private final PendingPostQueue queue;
        private final EventBus eventBus;
    
        AsyncPoster(EventBus eventBus) {
            this.eventBus = eventBus;
            queue = new PendingPostQueue();
        }
    
        public void enqueue(Subscription subscription, Object event) {
            PendingPost pendingPost = PendingPost.obtainPendingPost(subscription, event);
            queue.enqueue(pendingPost);
            eventBus.getExecutorService().execute(this);
        }
    
        @Override
        public void run() {
            PendingPost pendingPost = queue.poll();
            if(pendingPost == null) {
                throw new IllegalStateException("No pending post available");
            }
            eventBus.invokeSubscriber(pendingPost);
        }
    
    }
    

    Background Poster 랑 비슷 해 요.
    수신 자 처리 방법
        void invokeSubscriber(Subscription subscription, Object event) {
            try {
                subscription.subscriberMethod.method.invoke(subscription.subscriber, event);
            } catch (InvocationTargetException e) {
                handleSubscriberException(subscription, event, e.getCause());
            } catch (IllegalAccessException e) {
                throw new IllegalStateException("Unexpected exception", e);
            }
        }
    
  • PendingPost pendingPost = queue.poll(1000); 수신 자 를 호출 하 는 이벤트 수신 방법 (유사 반사)
  • 지연 이벤트 처리:
        void invokeSubscriber(PendingPost pendingPost) {
            Object event = pendingPost.event;
            Subscription subscription = pendingPost.subscription;
            PendingPost.releasePendingPost(pendingPost);
            if (subscription.active) {
                invokeSubscriber(subscription, event);
            }
        }
    

    중요 한 구성원 변수
        private static final EventBusBuilder DEFAULT_BUILDER = new EventBusBuilder();
        private static final Map, List>> eventTypesCache = new HashMap<>();
    
        private final Map, CopyOnWriteArrayList> subscriptionsByEventType;
        private final Map>> typesBySubscriber;
        private final Map, Object> stickyEvents;
    
        private final ThreadLocal currentPostingThreadState = new ThreadLocal() {
            @Override
            protected PostingThreadState initialValue() {
                return new PostingThreadState();
            }
        };
    
        private final HandlerPoster mainThreadPoster;
        private final BackgroundPoster backgroundPoster;
        private final AsyncPoster asyncPoster;
        private final SubscriberMethodFinder subscriberMethodFinder;
        private final ExecutorService executorService;
    
  • eventType: 실제 보 낸 이벤트 클래스 (CustomEvent. class)
  • DEFAULT_BUILDER: 기본 빌 더 대상
  • eventTypes Cache: 캐 시 EventType (이벤트 클래스. class) 과 EventType 하위 클래스, EventType 관련 인터페이스 클래스
  • subscriptions ByEvent Type: 이벤트 유형 (이벤트 클래스) 과 이벤트 수신 자 간 의 관 계 를 기록 합 니 다
  • types BySubscriber: 이벤트 수신 대상 (Object) 과 EventType (이벤트 클래스. class)
  • 기록
  • sticky Events: 점성 사건 기록
  • currentPostingThreadState: 스 레 드 상태 기록
  • mainThreadPoster: 메 인 스 레 드 이벤트 큐 관리 클래스 (이벤트 큐 를 저장 하고 이벤트 큐 에서 이 벤트 를 EventBus 에 처리 하 는 기능 이 있 습 니 다)
  • backgroundPoster: Background 이벤트 형식의 이벤트 큐 관리 클래스
  • AsyncPoster: Async 이벤트 형식의 이벤트 큐 관리 클래스
  • subscriberMethodFinder: 이벤트 수신 자 에서 이벤트 수신 방법 을 분석 (@ Subscribe 주 해 를 추가 하 는 방법), SubscriberMethod
  • 가 져 오기
  • executor Service: 스 레 드 탱크 의 역할 에 해당 하 며, 하위 스 레 드 에서 실 행 된 모든 이벤트
  • 를 수행 합 니 다.
    EventBusBuilder.class
    EventBus 만 들 기
    안에 저 장 된 매개 변 수 는 다음 과 같 습 니 다.
    SubscriberMethod.class
    수신 자 수신 방법 에 대한 패키지
    멤버 익숙:
        final Method method;
        final ThreadMode threadMode;
        final Class> eventType;
        final int priority;
        final boolean sticky;
        /** Used for efficient comparison */
        String methodString;
    
  • method: 수신 자 중의 이벤트 수신 방법, 이벤트 처 리 를 수행 할 때 호출
  • threadMode: 수용자 이벤트 수신 방법 이 어느 스 레 드 에서 실행 되 는 지 기록 합 니 다
  • priority: 우선 순위
  • sticky: 점성 사건 수신 방법 인지
  • methodString: 두 수신 방법 이 같은 지 비교 하기
  • Subscription.class
    이벤트 수신 자 (Object) 와 이벤트 수신 자 내부 이벤트 수신 방법 (SubscriberMethod) 을 봉 인 했 습 니 다.
    구성원 변수
        final Object subscriber;
        final SubscriberMethod subscriberMethod;
    
  • subscriber: 이벤트 수신 자
  • subscriberMethod: 이벤트 수신 자 중의 이벤트 수신 방법
  • PostingThreadState.class
    역할:
  • 안에 이벤트 대기 열 이 있 습 니 다. EventBus 가 보 낸 데 이 터 는 대기 열 에 저 장 됩 니 다 method.invoke
  • 스 레 드 상태 기록
  •     /** For ThreadLocal, much faster to set (and get multiple values). */
        final static class PostingThreadState {
            final List eventQueue = new ArrayList();
            boolean isPosting;
            boolean isMainThread;
            Subscription subscription;
            Object event;
            boolean canceled;
        }
    
  • isMainThread: 현재 스 레 드 가 주 스 레 드 인지 기록 (EventBus post 방법 에서 초기 화)
  • isPosting: 이벤트 발송 중 여부
  •     private final ThreadLocal currentPostingThreadState = new ThreadLocal() {
            @Override
            protected PostingThreadState initialValue() {
                return new PostingThreadState();
            }
        };
    

    ThreadLocal 을 사용 하여 스 레 드 내부 의 단일 예 를 실현 합 니 다. (하나의 스 레 드 에 하나의 PostingThreadState 만 있 음 을 보증 합 니 다)
    ExecutorService.class
    비동기 실행 체 제 를 설명 하고 임 무 를 배경 에서 수행 할 수 있 습 니 다.스 레 드 풀 과 유사 합 니 다.
    PendingPost.class
    지연 이벤트 입 니 다. 바로 처리 되 지 않 는 이 벤트 는 PendingPost 대상 으로 봉 인 됩 니 다. 지정 한 이벤트 대기 열 에 놓 여 처 리 를 기다 리 게 합 니 다.
    Subscription -》PendingPost
        static PendingPost obtainPendingPost(Subscription subscription, Object event) {
            synchronized (pendingPostPool) {
                int size = pendingPostPool.size();
                if (size > 0) {
                    PendingPost pendingPost = pendingPostPool.remove(size - 1);
                    pendingPost.event = event;
                    pendingPost.subscription = subscription;
                    pendingPost.next = null;
                    return pendingPost;
                }
            }
            return new PendingPost(event, subscription);
        }
    

    지연 이벤트 가 처 리 될 때 는 먼저 PendingPost 에서 Subscription 을 가 져 와 야 합 니 다.
    Subscription subscription = pendingPost.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);
                }
            }
        }
    

    구조 방법
        private PendingPost(Object event, Subscription subscription) {
            this.event = event;
            this.subscription = subscription;
        }
    

    개인 적 인 것 입 니 다. 정적 인 방법 으로 만 PendingPost 를 만 들 수 있 습 니 다.
    구성원 변수
    private final static List pendingPostPool = new ArrayList();
    
        Object event;
        Subscription subscription;
        PendingPost next;
    
  • pendingPost Pool: 지연 이벤트 풀 은 대상 이 성능 에 대한 소 모 를 적 게 만 듭 니 다.
  • 이벤트: 사용자 가 보 낸 이벤트 대상
  • PendingPost Queue. class 이벤트 대기 열의 실현
    final class PendingPostQueue {
        private PendingPost head;
        private PendingPost tail;
    
        synchronized void enqueue(PendingPost pendingPost) {
            if (pendingPost == null) {
                throw new NullPointerException("null cannot be enqueued");
            }
            if (tail != null) {
                tail.next = pendingPost;
                tail = pendingPost;
            } else if (head == null) {
                head = tail = pendingPost;
            } else {
                throw new IllegalStateException("Head present, but no tail");
            }
            notifyAll();
        }
    
        synchronized PendingPost poll() {
            PendingPost pendingPost = head;
            if (head != null) {
                head = head.next;
                if (head == null) {
                    tail = null;
                }
            }
            return pendingPost;
        }
    
        synchronized PendingPost poll(int maxMillisToWait) throws InterruptedException {
            if (head == null) {
                wait(maxMillisToWait);
            }
            return poll();
        }
    
    }
    

    단일 체인 구조
  • 대기 열 에 하나의 사건 만 있 을 때 head, tail 은 같은 사건 대상 eventQueue 을 가리 키 고 그들의 next 는 모두 null
  • 을 가리킨다.
  • 대기 열 에서 사건 = 2 일 때 head. next 는 두 번 째 사건 을 가리 키 고 tail. next 는 자신 을 가리킨다
  • 대기 열 에서 이벤트 > 2 일 때 마지막 이벤트 (tail. next 가 자신 을 가리 키 는 것), 중간 이벤트 (mid. next 가 다음 사건 을 가리 키 는 것)
  • SubscriberMethodFinder
    역할: 이벤트 수신 자 에서 모든 이벤트 수신 방법 을 얻 을 수 있 습 니 다 head = tail = pendingPost;

    좋은 웹페이지 즐겨찾기