Netty源码分析-GlobalEventExecutor

 

GlobalEventExecutor源码分析,GlobalEventExecutor内部只有一个线程执行队列中的任务,如果队列超过1秒没有新的任务,那么线程会结束, 此时如果再有新的任务加入,则会创建新的线程继续执行。


package io.netty.util.concurrent;

import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;

import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Queue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

//当任务队列中没有待处理的任务,1秒钟后,它将关闭线程,有新的任务加入,线程重新创建并启动
public final class GlobalEventExecutor extends AbstractScheduledEventExecutor {

    private static final InternalLogger logger = InternalLoggerFactory.getInstance(GlobalEventExecutor.class);

    //一秒钟转为纳秒 1000000000
    private static final long SCHEDULE_QUIET_PERIOD_INTERVAL = TimeUnit.SECONDS.toNanos(1);

    //单例模式
    public static final GlobalEventExecutor INSTANCE = new GlobalEventExecutor();

    //链表阻塞队列
    final BlockingQueue<Runnable> taskQueue = new LinkedBlockingQueue<Runnable>();

    //一个任务,第一个参数表示1秒后到执行时间,第二个参数表示每次执行间隔1秒。
    final ScheduledFutureTask<Void> quietPeriodTask = new ScheduledFutureTask<Void>(
            this, Executors.<Void>callable(new Runnable() {
        @Override
        public void run() {
            // NOOP
        }
    }, null), ScheduledFutureTask.deadlineNanos(SCHEDULE_QUIET_PERIOD_INTERVAL), -SCHEDULE_QUIET_PERIOD_INTERVAL);

    //线程工厂,负责创建线程
    final ThreadFactory threadFactory =
            new DefaultThreadFactory(DefaultThreadFactory.toPoolName(getClass()), false, Thread.NORM_PRIORITY, null);

    //任务执行器
    private final TaskRunner taskRunner = new TaskRunner();

    //线程是否已经启动
    private final AtomicBoolean started = new AtomicBoolean();

    //当前正在运行的线程
    volatile Thread thread;

    //一个固定是失败的Futrue对象
    private final Future<?> terminationFuture = new FailedFuture<Object>(this, new UnsupportedOperationException());

    //构造参数把quietPeriodTask加入到底层队列,底层队列是有顺序的
    //根据quietPeriodTask它判断底层队列是否还有新的任务
    private GlobalEventExecutor() {
        //这里调用了scheduledTaskQueue()方法,底层已经创建了scheduledTaskQueue
        //并把noop标记作用的队列加入到父类排序队列,这个任务永远不会删除,每次运行后1秒以后再次运行。
        //它的作用是排序,它出现了说明系统过了1秒,可以结合队列的数量判断队列1秒过后是否还有任务。
        scheduledTaskQueue().add(quietPeriodTask);
    }

    /**
     * Take the next {@link Runnable} from the task queue and so will block if no task is currently present.
     *
     * @return {@code null} if the executor thread has been interrupted or waken up.
     */
    Runnable takeTask() {
        //本类链表队列
        BlockingQueue<Runnable> taskQueue = this.taskQueue;
        for (;;) {
            //父类排序度列,取出头元素但不移除元素
            ScheduledFutureTask<?> scheduledTask = peekScheduledTask();

            //元素为null,则在本类链表队列上阻塞
            //不过 由于上面已经加入了quietPeriodTask,所以这里永远不为null
            if (scheduledTask == null) {
                Runnable task = null;
                try {
                    //阻塞
                    task = taskQueue.take();
                } catch (InterruptedException e) {
                    // Ignore
                }
                return task;
            } else {
                //获取元素距离可以执行的时间毫秒数
                long delayNanos = scheduledTask.delayNanos();
                Runnable task;
                //如果delayNanos>0说明没到执行时间
                if (delayNanos > 0) {
                    try {
                        //在q中等到delayNanos这么久,看是否有新的任务
                        task = taskQueue.poll(delayNanos, TimeUnit.NANOSECONDS);
                    } catch (InterruptedException e) {
                        // Waken up.
                        return null;
                    }
                } else {
                    //如果已到执行时间,立即去q中获取元素
                    task = taskQueue.poll();
                }

                //如果到时间本地task中没有元素,从父类q中获取到期可执行的元素。
                if (task == null) {
                    fetchFromScheduledTaskQueue();
                    //然后再次获取本地队列元素
                    task = taskQueue.poll();
                }

                //还为null则继续循环,这里会返回quietPeriodTask
                if (task != null) {
                    return task;
                }
            }
        }
    }

    //从父类可排序队列中获取到期可执行的任务
    private void fetchFromScheduledTaskQueue() {
        long nanoTime = AbstractScheduledEventExecutor.nanoTime();
        //从父类可排序队列中获取到期可执行的任务
        Runnable scheduledTask = pollScheduledTask(nanoTime);
        //如果父类存在到期可执行任务,循环加入到本列链表队列
        while (scheduledTask != null) {
            taskQueue.add(scheduledTask);
            scheduledTask = pollScheduledTask(nanoTime);
        }
    }

   
    public int pendingTasks() {
        return taskQueue.size();
    }


    private void addTask(Runnable task) {
        if (task == null) {
            throw new NullPointerException("task");
        }
        taskQueue.add(task);
    }

    @Override
    public boolean inEventLoop(Thread thread) {
        return thread == this.thread;
    }

    @Override
    public Future<?> shutdownGracefully(long quietPeriod, long timeout, TimeUnit unit) {
        return terminationFuture();
    }

    @Override
    public Future<?> terminationFuture() {
        return terminationFuture;
    }

    @Override
    @Deprecated
    public void shutdown() {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean isShuttingDown() {
        return false;
    }

    @Override
    public boolean isShutdown() {
        return false;
    }

    @Override
    public boolean isTerminated() {
        return false;
    }

    @Override
    public boolean awaitTermination(long timeout, TimeUnit unit) {
        return false;
    }

    /**
     * Waits until the worker thread of this executor has no tasks left in its task queue and terminates itself.
     * Because a new worker thread will be started again when a new task is submitted, this operation is only useful
     * when you want to ensure that the worker thread is terminated <strong>after</strong> your application is shut
     * down and there's no chance of submitting a new task afterwards.
     *
     * @return {@code true} if and only if the worker thread has been terminated
     */
    public boolean awaitInactivity(long timeout, TimeUnit unit) throws InterruptedException {
        if (unit == null) {
            throw new NullPointerException("unit");
        }

        final Thread thread = this.thread;
        if (thread == null) {
            throw new IllegalStateException("thread was not started");
        }
        thread.join(unit.toMillis(timeout));
        return !thread.isAlive();
    }

    //执行任务,加入队列,如果当前执行器没启动则启动
    @Override
    public void execute(Runnable task) {
        if (task == null) {
            throw new NullPointerException("task");
        }

        addTask(task);
        if (!inEventLoop()) {
            startThread();
        }
    }

    private void startThread() {
        //原子判断线程是否启动,返回true说明之前没启动
        if (started.compareAndSet(false, true)) {

            //创建线程,传入taskRunner
            final Thread t = threadFactory.newThread(taskRunner);
            // Set to null to ensure we not create classloader leaks by holds a strong reference to the inherited
            // classloader.
            // See:
            // - https://github.com/netty/netty/issues/7290
            // - https://bugs.openjdk.java.net/browse/JDK-7008595
            AccessController.doPrivileged(new PrivilegedAction<Void>() {
                @Override
                public Void run() {
                    t.setContextClassLoader(null);
                    return null;
                }
            });

            // Set the thread before starting it as otherwise inEventLoop() may return false and so produce
            // an assert error.
            // See https://github.com/netty/netty/issues/4357
            //启动线程
            thread = t;
            t.start();
        }
    }


    //任务执行器
    final class TaskRunner implements Runnable {
        @Override
        public void run() {
            for (;;) {
                //获取可执行任务
                Runnable task = takeTask();
                if (task != null) {
                    try {
                        //任务不为空先运行一波:)
                        task.run();
                    } catch (Throwable t) {
                        logger.warn("Unexpected exception from the global event executor: ", t);
                    }

                    //如果Task不是quietPeriodTask对象,则继续循环
                    //如果是quietPeriodTask对象,说明1秒时间过了没有其它任务,需要判断队列是否已经空了,如果空了则结束线程。
                    if (task != quietPeriodTask) {
                        continue;
                    }
                }

                Queue<ScheduledFutureTask<?>> scheduledTaskQueue = GlobalEventExecutor.this.scheduledTaskQueue;
                // Terminate if there is no task in the queue (except the noop task).
                //如果类队列为空,父类队列只有noop-task(quietPeriodTask),说明已经没用后续任务了
                if (taskQueue.isEmpty() && (scheduledTaskQueue == null || scheduledTaskQueue.size() == 1)) {
                    // Mark the current thread as stopped.
                    // The following CAS must always success and must be uncontended,
                    // because only one thread should be running at the same time.

                    //关闭标记位,这个方法肯定会成功,并且无需竞争,因为只有一个线程会设置它。
                    boolean stopped = started.compareAndSet(true, false);
                    //确保设置成功,否则异常
                    assert stopped;

                    //如果在此时刻,其它现成调用了execute方法,那么队列数量会增加,就不会进入下面方法。
                    // Check if there are pending entries added by execute() or schedule*() while we do CAS above.
                    if (taskQueue.isEmpty() && (scheduledTaskQueue == null || scheduledTaskQueue.size() == 1)) {
                        // A) No new task was added and thus there's nothing to handle
                        //    -> safe to terminate because there's nothing left to do
                        // B) A new thread started and handled all the new tasks.
                        //    -> safe to terminate the new thread will take care the rest
                        //这里是正常情况,直接结算线程。
                        break;
                    }


                    //如果上面没有退出,代码执行到这里了,说明其它线程已经调用了execute方法
                    //当前任务队列出现了可执行的任务,那么尝试设置开关为true,设置成功则不退出循环,那么当前线程继续工作
                    //如果设置失败,则退出线程,交由新创建的线程执行。
                    // There are pending tasks added again.
                    if (!started.compareAndSet(false, true)) {
                        // startThread() started a new thread and set 'started' to true.
                        // -> terminate this thread so that the new thread reads from taskQueue exclusively.
                        break;
                    }

                    // New tasks were added, but this worker was faster to set 'started' to true.
                    // i.e. a new worker thread was not started by startThread().
                    // -> keep this thread alive to handle the newly added entries.
                }
            }
        }
    }
}

 

FastThreadLocal 是 Netty 中的一个优化版 ThreadLocal 实现。与 JDK 自带的 ThreadLocal 相比,FastThreadLocal 在性能上有所提升。 FastThreadLocal 的性能优势主要体现在以下几个方面: 1. 线程安全性:FastThreadLocal 使用了一种高效的方式来保证线程安全,避免了使用锁的开销,使得在高并发场景下性能更好。 2. 内存占用:FastThreadLocal 的内部数据结构更加紧凑,占用的内存更少,减少了对堆内存的占用,提高了内存的利用效率。 3. 访问速度:FastThreadLocal 在访问时,使用了直接索引的方式,避免了哈希表查找的开销,使得访问速度更快。 在 Netty 源码中,FastThreadLocal 主要被用于优化线程的局部变量存储,提高线程之间的数据隔离性和访问效率。通过使用 FastThreadLocal,Netty 在高性能的网络通信中能够更好地管理线程的局部变量,提供更高的性能和并发能力。 引用中提到的代码片段展示了 Netty 中的 InternalThreadLocalMap 的获取方式。如果当前线程是 FastThreadLocalThread 类型的线程,那么就直接调用 fastGet 方法来获取 InternalThreadLocalMap 实例;否则,调用 slowGet 方法来获取。 fastGet 方法中,会先尝试获取线程的 threadLocalMap 属性,如果不存在则创建一个新的 InternalThreadLocalMap,并设置为线程的 threadLocalMap 属性。最后返回获取到的 threadLocalMap。 slowGet 方法中,通过调用 UnpaddedInternalThreadLocalMap.slowThreadLocalMap 的 get 方法来获取 InternalThreadLocalMap 实例。如果获取到的实例为 null,则创建一个新的 InternalThreadLocalMap,并将其设置到 slowThreadLocalMap 中。最后返回获取到的 InternalThreadLocalMap。 综上所述,FastThreadLocal 是 Netty 中为了优化线程局部变量存储而设计的一种高性能的 ThreadLocal 实现。它通过减少锁的开销、优化内存占用和加快访问速度来提升性能。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [FastThreadLocal源码分析](https://blog.csdn.net/lvlei19911108/article/details/118021402)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [Netty 高性能之道 FastThreadLocal 源码分析(快且安全)](https://blog.csdn.net/weixin_33871366/article/details/94653953)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值