netty應用退出

netty程序,使用shutdownGracefully退出。退出前會把隊列中的消息發送完,釋放channel,多路複用器的去註冊,清空定時器任務等。

    public Future<?> shutdownGracefully(long quietPeriod, long timeout, TimeUnit unit) {
        EventExecutor[] var6 = this.children;
        int var7 = var6.length;

        for(int var8 = 0; var8 < var7; ++var8) {
            EventExecutor l = var6[var8];
            l.shutdownGracefully(quietPeriod, timeout, unit);
        }

        return this.terminationFuture();
    }

shutdownGracefully實現在NioEventLoop的父類SingleThreadEventExecutor中,

首先是改變state,爲了防止併發問題,這裏是netty 4,採用的原子類自旋的方式避免加鎖。

public Future<?> shutdownGracefully(long quietPeriod, long timeout, TimeUnit unit) {
        ObjectUtil.checkPositiveOrZero(quietPeriod, "quietPeriod");
        if(timeout < quietPeriod) {
            throw new IllegalArgumentException("timeout: " + timeout + " (expected >= quietPeriod (" + quietPeriod + "))");
        } else {
            ObjectUtil.checkNotNull(unit, "unit");
            if(this.isShuttingDown()) {
                return this.terminationFuture();
            } else {
                boolean inEventLoop = this.inEventLoop();

                boolean wakeup;
                int oldState;
                int newState;
                do {
                    if(this.isShuttingDown()) {
                        return this.terminationFuture();
                    }

                    wakeup = true;
                    oldState = this.state;
                    if(inEventLoop) {
                        newState = 3;
                    } else {
                        switch(oldState) {
                        case 1:
                        case 2:
                            newState = 3;
                            break;
                        default:
                            newState = oldState;
                            wakeup = false;
                        }
                    }
                } while(!STATE_UPDATER.compareAndSet(this, oldState, newState));

                this.gracefulShutdownQuietPeriod = unit.toNanos(quietPeriod);
                this.gracefulShutdownTimeout = unit.toNanos(timeout);
                if(this.ensureThreadStarted(oldState)) {
                    return this.terminationFuture;
                } else {
                    if(wakeup) {
                        this.taskQueue.offer(WAKEUP_TASK);
                        if(!this.addTaskWakesUp) {
                            this.wakeup(inEventLoop);
                        }
                    }

                    return this.terminationFuture();
                }
            }
        }
    }

喚醒selector,由NioEventLoop實現。

 protected void wakeup(boolean inEventLoop) {
        if(!inEventLoop && this.nextWakeupNanos.getAndSet(-1L) != -1L) {
            this.selector.wakeup();
        }

    }

狀態改變之後, run方法中檢測到狀態變化,執行closeAll方法

if(this.isShuttingDown()) {
                        this.closeAll();
                        if(this.confirmShutdown()) {
                            return;
                        }
                    }

獲取channel,如果是nioChannel,則調用unsafe的close方法。

 private void closeAll() {
        this.selectAgain();
        Set<SelectionKey> keys = this.selector.keys();
        Collection<AbstractNioChannel> channels = new ArrayList(keys.size());
        Iterator var3 = keys.iterator();

        while(var3.hasNext()) {
            SelectionKey k = (SelectionKey)var3.next();
            Object a = k.attachment();
            if(a instanceof AbstractNioChannel) {
                channels.add((AbstractNioChannel)a);
            } else {
                k.cancel();
                NioTask<SelectableChannel> task = (NioTask)a;
                invokeChannelUnregistered(task, k, (Throwable)null);
            }
        }

        var3 = channels.iterator();

        while(var3.hasNext()) {
            AbstractNioChannel ch = (AbstractNioChannel)var3.next();
            ch.unsafe().close(ch.unsafe().voidPromise());
        }

    }

AbstractChannel中的內部類AbstractUnsafe的close和voidPromise方法

public final void close(ChannelPromise promise) {
            this.assertEventLoop();
            ClosedChannelException closedChannelException = new ClosedChannelException();
            this.close(promise, closedChannelException, closedChannelException, false);
        }
 public final ChannelPromise voidPromise() {
            this.assertEventLoop();
            return AbstractChannel.this.unsafeVoidPromise;
        }

判斷當前鏈路中是否有未發送的消息,如果有則稍後再取消註冊,將任務放到task中。
關閉鏈路

private void close(final ChannelPromise promise, final Throwable cause, final ClosedChannelException closeCause, final boolean notify) {
            if(promise.setUncancellable()) {
                if(AbstractChannel.this.closeInitiated) {
                    if(AbstractChannel.this.closeFuture.isDone()) {
                        this.safeSetSuccess(promise);
                    } else if(!(promise instanceof VoidChannelPromise)) {
                        AbstractChannel.this.closeFuture.addListener(new ChannelFutureListener() {
                            public void operationComplete(ChannelFuture future) throws Exception {
                                promise.setSuccess();
                            }
                        });
                    }

                } else {
                    AbstractChannel.this.closeInitiated = true;
                    final boolean wasActive = AbstractChannel.this.isActive();
                    final ChannelOutboundBuffer outboundBuffer = this.outboundBuffer;
                    //清空發送隊列
                    this.outboundBuffer = null;
                    Executor closeExecutor = this.prepareToClose();
                    if(closeExecutor != null) {
                        closeExecutor.execute(new Runnable() {
                            public void run() {
                                try {
                                    AbstractUnsafe.this.doClose0(promise);
                                } finally {
                                    AbstractUnsafe.this.invokeLater(new Runnable() {
                                        public void run() {
                                            if(outboundBuffer != null) {
                                                outboundBuffer.failFlushed(cause, notify);
                                                outboundBuffer.close(closeCause);
                                            }

                                            AbstractUnsafe.this.fireChannelInactiveAndDeregister(wasActive);
                                        }
                                    });
                                }

                            }
                        });
                    } else {
                        try {
                            this.doClose0(promise);
                        } finally {
                            if(outboundBuffer != null) {
                                outboundBuffer.failFlushed(cause, notify);
                                outboundBuffer.close(closeCause);
                            }

                        }

                        if(this.inFlush0) {
                            this.invokeLater(new Runnable() {
                                public void run() {
                                    AbstractUnsafe.this.fireChannelInactiveAndDeregister(wasActive);
                                }
                            });
                        } else {
                        //觸發鏈路關閉通知事件,從多路複用器取消selectionKey
                            this.fireChannelInactiveAndDeregister(wasActive);
                        }
                    }

                }
            }
        }

從多路複用器取消selectionKey

 protected void doDeregister() throws Exception {
        this.eventLoop().cancel(this.selectionKey());
    }

關閉鏈路之後

protected boolean confirmShutdown() {
        if(!this.isShuttingDown()) {
            return false;
        } else if(!this.inEventLoop()) {
            throw new IllegalStateException("must be invoked from an event loop");
        } else {
            this.cancelScheduledTasks();
            if(this.gracefulShutdownStartTime == 0L) {
                this.gracefulShutdownStartTime = ScheduledFutureTask.nanoTime();
            }

            if(!this.runAllTasks() && !this.runShutdownHooks()) {
                long nanoTime = ScheduledFutureTask.nanoTime();
                if(!this.isShutdown() && nanoTime - this.gracefulShutdownStartTime <= this.gracefulShutdownTimeout) {
                
                    if(nanoTime - this.lastExecutionTime <= this.gracefulShutdownQuietPeriod) {//若沒有達到指定時間,則先不退出
                        this.taskQueue.offer(WAKEUP_TASK);

                        try {
                            Thread.sleep(100L);
                        } catch (InterruptedException var4) {
                            ;
                        }

                        return false;
                    } else {
                        return true;
                    }
                } else {
                    return true;
                }
            } else if(this.isShutdown()) {
                return true;
            } else if(this.gracefulShutdownQuietPeriod == 0L) {
                return true;
            } else {
                this.taskQueue.offer(WAKEUP_TASK);
                return false;
            }
        }
    }

執行尚在taskQueue中的任務,

 do {
 //    PriorityQueue<ScheduledFutureTask<?>> scheduledTaskQueue;
            fetchedAll = this.fetchFromScheduledTaskQueue();//取出隊列scheduledTaskQueue中所有的任務,放到taskQueue中。
            if(this.runAllTasksFrom(this.taskQueue)) {
                ranAtLeastOne = true;
            }
        } while(!fetchedAll);

執行taskQueue中的所有任務

//Queue<Runnable> taskQueue
protected final boolean runAllTasksFrom(Queue<Runnable> taskQueue) {
        Runnable task = pollTaskFrom(taskQueue);
        if(task == null) {
            return false;
        } else {
            do {
                safeExecute(task);
                task = pollTaskFrom(taskQueue);
            } while(task != null);

            return true;
        }
    }

執行註冊到nioeventLoop中的任務

private boolean runShutdownHooks() {
        boolean ran = false;

        while(!this.shutdownHooks.isEmpty()) {
            List<Runnable> copy = new ArrayList(this.shutdownHooks);
            this.shutdownHooks.clear();
            Iterator var3 = copy.iterator();

            while(var3.hasNext()) {
                Runnable task = (Runnable)var3.next();

                try {
                    task.run();
                } catch (Throwable var9) {
                    logger.warn("Shutdown hook raised an exception.", var9);
                } finally {
                    ran = true;
                }
            }
        }

        if(ran) {
            this.lastExecutionTime = ScheduledFutureTask.nanoTime();
        }

        return ran;
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章