Netty源码分析(一)之NioEventLoopGroup

netty版本

  1. 使用的netty版本是io.netty:netty-all:4.1.33.Final

NioEventLoopGroup

  1. 继承关系

  2. uml图

NioEventLoopGroup调用分析

  1. NioEventLoopGroup无参构造方法分析

    	NioEventLoopGroup构造方法调用
    	public NioEventLoopGroup() {this(0);
    	}
    	public NioEventLoopGroup(int nThreads) {this(nThreads, (Executor) null);
        }
    	public NioEventLoopGroup(int nThreads, Executor executor) {this(nThreads, executor, SelectorProvider.provider());
        }
        public NioEventLoopGroup(int nThreads, Executor executor, final SelectorProvider selectorProvider,
                                 final SelectStrategyFactory selectStrategyFactory) {super(nThreads, executor, selectorProvider, selectStrategyFactory, RejectedExecutionHandlers.reject());
        }
        
       父类 MultithreadEventLoopGroup的构造方法
       protected MultithreadEventLoopGroup(int nThreads, Executor executor, Object... args) {super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, executor, args);
       }
       
       protected MultithreadEventExecutorGroup(int nThreads, Executor executor, Object... args) {this(nThreads, executor, DefaultEventExecutorChooserFactory.INSTANCE, args);
       }
        
    
    
    Main NioEventLoopGroup MultithreadE Main NioEventLoopGroup MultithreadE

DefaultEventExecutorChooserFactory

  1. DefaultEventExecutorChooserFactory用于选择下一个可用的EventExecutor, 其内部有两种选择器, 一个是基于位运算,一个是基于取模运算

    	//如果是2的幂次方就使用位运算否则使用取模运算
    	public EventExecutorChooser newChooser(EventExecutor[] executors) {
            if (isPowerOfTwo(executors.length)) {
                return new PowerOfTwoEventExecutorChooser(executors);
            } else {
                return new GenericEventExecutorChooser(executors);
            }
        }
        
        //判断一个数是否是2的幂次方
        private static boolean isPowerOfTwo(int val) {
            return (val & -val) == val;
        }
    	
    	private static final class PowerOfTwoEventExecutorChooser implements EventExecutorChooser {
    	        private final AtomicInteger idx = new AtomicInteger();
    	        private final EventExecutor[] executors;
    	
    	        PowerOfTwoEventExecutorChooser(EventExecutor[] executors) {
    	            this.executors = executors;
    	        }
    	
    	        @Override
    	        public EventExecutor next() {
    	            return executors[idx.getAndIncrement() & executors.length - 1];
    	        }
    	    }
    
        private static final class GenericEventExecutorChooser implements EventExecutorChooser {
            private final AtomicInteger idx = new AtomicInteger();
            private final EventExecutor[] executors;
    
            GenericEventExecutorChooser(EventExecutor[] executors) {
                this.executors = executors;
            }
    
            @Override
            public EventExecutor next() {
                return executors[Math.abs(idx.getAndIncrement() % executors.length)];
            }
        }
    

MultithreadEventLoopGroup核心代码分析

  1. NioEventLoopGroup无参构造方法默认传入的线程数为0,最终调用的是父类MultithreadEventLoopGroup的构造方法,当nThreads==0,如果没有设置系统属性io.netty.eventLoopThreads(通过-Dio.netty.eventLoopThreads设置),则此时会使用默认线程个数DEFAULT_EVENT_LOOP_THREADS

    DEFAULT_EVENT_LOOP_THREADS的计算规则
    private static final int DEFAULT_EVENT_LOOP_THREADS;
    static {
        DEFAULT_EVENT_LOOP_THREADS = Math.max(1, SystemPropertyUtil.getInt(
                "io.netty.eventLoopThreads", NettyRuntime.availableProcessors() * 2));
    
        if (logger.isDebugEnabled()) {
            logger.debug("-Dio.netty.eventLoopThreads: {}", DEFAULT_EVENT_LOOP_THREADS);
        }
    }
    
    
     
     protected MultithreadEventExecutorGroup(int nThreads, Executor executor,
                                            EventExecutorChooserFactory chooserFactory, Object... args) {
        if (nThreads <= 0) {
            throw new IllegalArgumentException(String.format("nThreads: %d (expected: > 0)", nThreads));
        }
    
        if (executor == null) {
            //通过DefaultThreadFactory创建线程
            executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
        }
    
        children = new EventExecutor[nThreads];
    
        for (int i = 0; i < nThreads; i ++) {
            boolean success = false;
            try {
                //初始化nThreads个线程,并存放在children数组中,newChild是抽象方法,由子类实现
                children[i] = newChild(executor, args);
                success = true;
            } catch (Exception e) {
                // TODO: Think about if this is a good exception type
                throw new IllegalStateException("failed to create a child event loop", e);
            } finally {
                if (!success) {
                    for (int j = 0; j < i; j ++) {
                        children[j].shutdownGracefully();
                    }
    
                    for (int j = 0; j < i; j ++) {
                        EventExecutor e = children[j];
                        try {
                            while (!e.isTerminated()) {
                                e.awaitTermination(Integer.MAX_VALUE, TimeUnit.SECONDS);
                            }
                        } catch (InterruptedException interrupted) {
                            // Let the caller handle the interruption.
                            Thread.currentThread().interrupt();
                            break;
                        }
                    }
                }
            }
        }
    	
        chooser = chooserFactory.newChooser(children);
    
        final FutureListener<Object> terminationListener = new FutureListener<Object>() {
            @Override
            public void operationComplete(Future<Object> future) throws Exception {
                if (terminatedChildren.incrementAndGet() == children.length) {
                    terminationFuture.setSuccess(null);
                }
            }
        };
    
        for (EventExecutor e: children) {
            e.terminationFuture().addListener(terminationListener);
        }
    
    	//为children数组维护一个只读视图readonlyChildren,主要用于迭代。
        Set<EventExecutor> childrenSet = new LinkedHashSet<EventExecutor>(children.length);
        Collections.addAll(childrenSet, children);
        readonlyChildren = Collections.unmodifiableSet(childrenSet);
    }
    
    
  2. mac下测试默认线程数,并通过命令确认

     	 @Test
        public void testThreadNum() {
            int DEFAULT_EVENT_LOOP_THREADS =  Math.max(1, SystemPropertyUtil.getInt(
                    "io.netty.eventLoopThreads", NettyRuntime.availableProcessors() * 2));
            //输出:16. 在超线程的4核Core i7返回NettyRuntime.availableProcessors()返回8
            System.out.println(DEFAULT_EVENT_LOOP_THREADS);
        }
    
    	通过命令查看mac cpu信息,4核,8线程。 
    	mac:~ jannal$ sysctl  machdep.cpu.core_count  machdep.cpu.thread_count
    	machdep.cpu.core_count: 4
    	machdep.cpu.thread_count: 8
    
  3. NioEventLoopGroup实现类的newChild(MultithreadEventLoopGroup有很多实现类,这里我们主要关注NioEventLoopGroup这个实现类).可以看出MultithreadEventLoopGroup中的一个children其实就是一组NioEventLoop对象,其实NioEventLoop就是一个线程,而NioEventLoopGroup就是一个线程池,NioEventLoop在后面单独分析

        @Override
        protected EventLoop newChild(Executor executor, Object... args) throws Exception {
            return new NioEventLoop(this, executor, (SelectorProvider) args[0],
                ((SelectStrategyFactory) args[1]).newSelectStrategy(), (RejectedExecutionHandler) args[2]);
        }
    

ThreadPerTaskExecutor

  1. ThreadPerTaskExecutor实现了jdk的Executor接口,内部通过ThreadFactory来启动一个线程,在MultithreadEventLoopGroup中通过newDefaultThreadFactory()创建一个DefaultThreadFactory传入ThreadPerTaskExecutor构造方法中

    	public final class ThreadPerTaskExecutor implements Executor {
    	    private final ThreadFactory threadFactory;
    	
    	    public ThreadPerTaskExecutor(ThreadFactory threadFactory) {
    	        if (threadFactory == null) {
    	            throw new NullPointerException("threadFactory");
    	        }
    	        this.threadFactory = threadFactory;
    	    }
    	
    	    @Override
    	    public void execute(Runnable command) {
    	        threadFactory.newThread(command).start();
    	    }
    	}	
    

从构造方法可以看出,ThreadPerTaskExecutor每次执行任务时候都会创建一个Thread

DefaultThreadFactory

  1. Netty中默认的ThreadFactory,newThread是通过FastThreadLocalThread来创建一个Thread。

        @Override
        public Thread newThread(Runnable r) {
            Thread t = newThread(FastThreadLocalRunnable.wrap(r), prefix + nextId.incrementAndGet());
            try {
                if (t.isDaemon() != daemon) {
                    t.setDaemon(daemon);
                }
    
                if (t.getPriority() != priority) {
                    t.setPriority(priority);
                }
            } catch (Exception ignored) {
                // Doesn't matter even if failed to set.
            }
            return t;
        }
        protected Thread newThread(Runnable r, String name) {
            return new FastThreadLocalThread(threadGroup, r, name);
        }
    
  2. 构造方法,线程名字的前缀

        public DefaultThreadFactory(String poolName, boolean daemon, int priority, ThreadGroup threadGroup) {
            if (poolName == null) {
                throw new NullPointerException("poolName");
            }
            if (priority < Thread.MIN_PRIORITY || priority > Thread.MAX_PRIORITY) {
                throw new IllegalArgumentException(
                        "priority: " + priority + " (expected: Thread.MIN_PRIORITY <= priority <= Thread.MAX_PRIORITY)");
            }
            //命名规则poolName-1-xxx
            prefix = poolName + '-' + poolId.incrementAndGet() + '-';
            this.daemon = daemon;
            this.priority = priority;
            this.threadGroup = threadGroup;
        }
    
    

总结

  1. NioEventLoopGroup执行逻辑
    • 不指定线程数,默认赋值0,此时nThread=CPU*2
    • 创建ThreadPerTaskExecutor
    • 根据nThread创建多个NioEventLoop,并保存在children数组中
    • 根据children数组的大小获取下一个Excutor的选择策略,即选择NioEventLoop的策略
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值