2022-05-29_netty中SingleThreadEventExecutor线程创建过程分析学习笔记

20220529_netty中SingleThreadEventExecutor线程创建过程分析学习笔记

1概述

SingleThreadEventExecutor线程本质就是原生ThreadPoolExecutor线程的创建。

可借助章节2测试代码进行源码走读,本节主要有一下几点:

  1. ThreadPoolExecutor线程的创建、任务的提交
  2. SingleThreadEventExecutor线程的创建、任务的提交
image-20220529201819422.png

1.1ThreadPoolExecutor线程的创建、任务的提交

1.1.1ThreadPoolExecutor内置threadFactory

 public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);
    }

1.1.2newThread创建线程的方法

static class DefaultThreadFactory implements ThreadFactory {
        private static final AtomicInteger poolNumber = new AtomicInteger(1);
        private final ThreadGroup group;
        private final AtomicInteger threadNumber = new AtomicInteger(1);
        private final String namePrefix;

        DefaultThreadFactory() {
            SecurityManager s = System.getSecurityManager();
            group = (s != null) ? s.getThreadGroup() :
                                  Thread.currentThread().getThreadGroup();
            // 线程名称:pool-1-thread-1
            namePrefix = "pool-" +
                          poolNumber.getAndIncrement() +
                         "-thread-";
        }

        // 创建线程
        public Thread newThread(Runnable r) {
            Thread t = new Thread(group, r,
                                  namePrefix + threadNumber.getAndIncrement(),
                                  0);
            if (t.isDaemon())
                t.setDaemon(false);
            if (t.getPriority() != Thread.NORM_PRIORITY)
                t.setPriority(Thread.NORM_PRIORITY);
            return t;
        }
    }

1.1.3真正Jdk线程创建的地方

// C:\Program Files\Java\jdk1.8.0_60\src.zip!\java\util\concurrent\ThreadPoolExecutor.java
public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
    if (addWorker(command, true))
private boolean addWorker(Runnable firstTask, boolean core) {
        retry:
        for (;;) {
        }
        boolean workerStarted = false;
        boolean workerAdded = false;
        Worker w = null;
        try {
            w = new Worker(firstTask);  // 开始创建线程
 /**
         * Creates with given first task and thread from ThreadFactory.
         * @param firstTask the first task (null if none)
         */
        Worker(Runnable firstTask) {
            setState(-1); // inhibit interrupts until runWorker
            this.firstTask = firstTask;
            this.thread = getThreadFactory().newThread(this); // 调用1.2.2中的方法
        }

1.2SingleThreadEventExecutor线程的创建、任务的提交

// 确保线程值启动一次,并发安全性  
private static final AtomicIntegerFieldUpdater<SingleThreadEventExecutor> STATE_UPDATER =
            AtomicIntegerFieldUpdater.newUpdater(SingleThreadEventExecutor.class, "state");
image-20220529201112198.png
image-20220529201131131.png

1.2.1SingleThreadEventExecutor抽象类关系图

image-20220330140953543.png
  1. SingleThreadEventExecutor抽象类:延时任务,获取待执行和过期任务,并执行,内置Queue<Runnable> taskQueue。

  2. SingleThreadEventLoop抽象类:实现EventLoopGroup接口中的next,注册等方法,内置额外的时间循环任务队列,tailTasks queue<Runnable>,作为参数给SingleThreadEventExecutor.runAllTasksFrom调用,问题来了,taskQueue不够吗?

    protected final boolean runAllTasksFrom(Queue<Runnable> taskQueue) {。
    
  1. DefaultEventLoop:无限循环,实现从队列中取任务,执行任务等一些列的。
// E:\workdirectory\Dev\study\netty-4.1\transport\src\main\java\io\netty\channel\DefaultEventLoop.java

// 实现了SingleThreadEventExecutor抽象类的run方法。
@Override
    protected void run() {
        for (;;) {
            // 1.调用SingleThreadEventExecutor.takeTask获取任务。
            Runnable task = takeTask();
            if (task != null) {
                task.run();
                // 3.调用SingleThreadEventExecutor.updateLastExecutionTime
                updateLastExecutionTime();
            }

            // 3.调用SingleThreadEventExecutor.confirmShutdown
            if (confirmShutdown()) {
                break;
            }
        }
    }

1.2.2线程的创建逻辑

1.2.2.1构建SingleThreadEventExecutor执行器

@Test
    public void testWrappedExecutorIsShutdown() {
        // 1.设定一个线程
        ExecutorService executorService = Executors.newSingleThreadExecutor();

        final SingleThreadEventExecutor executor =
                        new SingleThreadEventExecutor(null, executorService, false) {

1.2.2.1包装原生Jdkexecutor

protected SingleThreadEventExecutor(EventExecutorGroup parent, Executor executor,
    // 线程执行器的包装类:ThreadExecutorMap
    // 参数1 executor:ThreadPerTaskExecutor
    // 参数2 this:SingleThreadEventExecutor
    this.executorWrap = ThreadExecutorMap.apply(executor, this);
    this.executor = ThreadExecutorMap.apply(executor, this);
// E:\workdirectory\Dev\study\netty-4.1\common\src\main\java\io\netty\util\internal\ThreadExecutorMap.java
return new Executor() {
    @Override
    public void execute(final Runnable command) {
        // step1:对原始 executor进行包装
        // 后面外界的入口execute-->apply、execute
        // 注意 threadPoolExecutor:java.util.concurrent.ThreadPoolExecutor
        // 提交任务的时候,会在这里创建线程,并执行这个runnable方法,runnable内部是一个取任务的无线循环
        // 但一直在这个工作线程中执行 while (!confirmShutdown()) {
        executor.execute(apply(command, eventExecutor));
    }
};
// E:\workdirectory\Dev\study\netty-4.1\common\src\main\java\io\netty\util\internal\ThreadExecutorMap.java
// apply逻辑分析,设置当前的事件执行器,返回业务runnable,并真正的线程池提交执行
public static Runnable apply(final Runnable command, final EventExecutor eventExecutor) {
        ObjectUtil.checkNotNull(command, "command");
        ObjectUtil.checkNotNull(eventExecutor, "eventExecutor");
        return new Runnable() {
            @Override
            public void run() {
                setCurrentEventExecutor(eventExecutor);
                try {
                    // step2:调用 doStartThread中的execute runnable,循环取任务执行
                    // command 实际为:@@@@@@那方法
                    command.run();
                } finally {
                    setCurrentEventExecutor(null);
                }
            }
        };
    }

1.2.2.2任务提交(首次进行线程创建)

// E:\workdirectory\Dev\study\netty-4.1\common\src\main\java\io\netty\util\concurrent\SingleThreadEventExecutor.java
private void execute(Runnable task, boolean immediate) { // immediate:true
        boolean inEventLoop = inEventLoop();
        addTask(task); // 业务的runnable方法
 private void execute(Runnable task, boolean immediate) {
        boolean inEventLoop = inEventLoop();
        addTask(task);
        if (!inEventLoop) {
            startThread();
    private void doStartThread() {
        assert thread == null;
        executor.execute(new Runnable() {  // 人工构建一个runnable任务,循环调用takeTask方法
// E:\workdirectory\Dev\study\netty-4.1\common\src\main\java\io\netty\util\concurrent\SingleThreadEventExecutor.java
private void doStartThread() {
        assert thread == null;
        // 执行 2.1.3中的方法
        executor.execute(
***********************************************************************  
            new Runnable() { 
           
            @Override
            public void run() { // 这个方法实际一直不会结束的@@@@@@
                thread = Thread.currentThread();
                if (interrupted) {
                    thread.interrupt();
                }

                boolean success = false;
                updateLastExecutionTime();
                try {
                    // 去队列里取任务执行
                    // 执行模板方法,实现类里的 SingleThreadEventLoopTest.java,for (;;) {
                    SingleThreadEventExecutor.this.run();
                    success = true;
                } catch (Throwable t) {
                    logger.warn("Unexpected exception from an event executor: ", t);
                } finally {
                    for (;;) {
                        int oldState = state;
                        if (oldState >= ST_SHUTTING_DOWN || STATE_UPDATER.compareAndSet(
                                SingleThreadEventExecutor.this, oldState, ST_SHUTTING_DOWN)) {
                            break;
                        }
                    }

                    // Check if confirmShutdown() was called at the end of the loop.
                    if (success && gracefulShutdownStartTime == 0) {
                        if (logger.isErrorEnabled()) {
                            logger.error("Buggy " + EventExecutor.class.getSimpleName() + " implementation; " +
                                    SingleThreadEventExecutor.class.getSimpleName() + ".confirmShutdown() must " +
                                    "be called before run() implementation terminates.");
                        }
                    }

                    try {
                        // Run all remaining tasks and shutdown hooks. At this point the event loop
                        // is in ST_SHUTTING_DOWN state still accepting tasks which is needed for
                        // graceful shutdown with quietPeriod.
                        for (;;) {
                            if (confirmShutdown()) {
                                break;
                            }
                        }

                        // Now we want to make sure no more tasks can be added from this point. This is
                        // achieved by switching the state. Any new tasks beyond this point will be rejected.
                        for (;;) {
                            int oldState = state;
                            if (oldState >= ST_SHUTDOWN || STATE_UPDATER.compareAndSet(
                                    SingleThreadEventExecutor.this, oldState, ST_SHUTDOWN)) {
                                break;
                            }
                        }

                        // We have the final set of tasks in the queue now, no more can be added, run all remaining.
                        // No need to loop here, this is the final pass.
                        confirmShutdown();
                    } finally {
                        try {
                            cleanup();
                        } finally {
                            // Lets remove all FastThreadLocals for the Thread as we are about to terminate and notify
                            // the future. The user may block on the future and once it unblocks the JVM may terminate
                            // and start unloading classes.
                            // See https://github.com/netty/netty/issues/6596.
                            FastThreadLocal.removeAll();

                            STATE_UPDATER.set(SingleThreadEventExecutor.this, ST_TERMINATED);
                            threadLock.countDown();
                            int numUserTasks = drainTasks();
                            if (numUserTasks > 0 && logger.isWarnEnabled()) {
                                logger.warn("An event executor terminated with " +
                                        "non-empty task queue (" + numUserTasks + ')');
                            }
                            terminationFuture.setSuccess(null);
                        }
                    }
                }
            }
        }
***********************************************************************
        );
    }

2测试代码

@Test
public void testWrappedExecutorIsShutdown() throws InterruptedException {
    // 1.构建ExecutorService
    ExecutorService executorService = Executors.newSingleThreadExecutor();

    // 2.构建SingleThreadEventExecutor
    final SingleThreadEventExecutor executor =
        new SingleThreadEventExecutor(null, executorService, false) {
        @Override
        protected void run() {
            while (!confirmShutdown()) {
                Runnable task = takeTask();
                if (task != null) {
                    task.run();
                }
            }
        }
    };
    // 3.任务提交
    executor.execute(new Runnable() {
        @Override
        public void run() {
            System.out.println("do it");
            // Noop.
        }
    });
    TimeUnit.SECONDS.sleep(100);
    executorService.shutdownNow();
    assertTrue(executor.isShutdown());

参考

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,290评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,399评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,021评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,034评论 0 207
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,412评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,651评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,902评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,605评论 0 199
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,339评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,586评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,076评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,400评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,060评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,083评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,851评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,685评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,595评论 2 270

推荐阅读更多精彩内容