Netty源码分析之NioEventLoopGroup创建

本文主要介绍了Netty中NioEventLoopGroup的创建过程。服务端通常创建两个NioEventLoopGroup,分别用于接收请求和处理网络IO等操作。详细阐述了其构造函数,包括线程数设置、线程构造器、child线程组创建和线程选择器创建等内容,还介绍了相关组件的作用。

NioEventLoopGroup的创建

  服务端一般是通过创建两个NioEventLoopGroup来创建NioEventLoop,一个NioEventLoopGroup主要是用于接收客户端的请求,另外一个NioEventLoopGroup则是处理网络IO的相关读写操作,或者是执行定时任务,或者是系统任务。

bossGroup = new NioEventLoopGroup();
workerGroup = new NioEventLoopGroup();

NioEventLoopGroup的构造函数:

public NioEventLoopGroup() {
    this(0);
}

public NioEventLoopGroup(int nThreads) {
    this(nThreads, (Executor)null);
}

public NioEventLoopGroup(int nThreads, ThreadFactory threadFactory) {
    this(nThreads, threadFactory, SelectorProvider.provider());
}

public NioEventLoopGroup(int nThreads, Executor executor) {
    this(nThreads, executor, SelectorProvider.provider());
}

public NioEventLoopGroup(int nThreads, ThreadFactory threadFactory, SelectorProvider selectorProvider) {
    this(nThreads, threadFactory, selectorProvider, DefaultSelectStrategyFactory.INSTANCE);
}

public NioEventLoopGroup(int nThreads, ThreadFactory threadFactory, SelectorProvider selectorProvider, SelectStrategyFactory selectStrategyFactory) {
    super(nThreads, threadFactory, new Object[]{selectorProvider, selectStrategyFactory, RejectedExecutionHandlers.reject()});
}

  可以从默认的构造函数看出来,默认传入的线程数是0,默认传入的ThreadFactory是null,并且传入了一个selectorProvider。最后层层调用了父类MultithreadEventLoopGroup的构造函数。

protected MultithreadEventLoopGroup(int nThreads, ThreadFactory threadFactory, Object... args) {
    super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, threadFactory, args);
}

   这里会判断传入的线程数是不是等于0,如果等于0,就将线程数设置为2*cpu。默认情况下不传参数,会创建2*cpu个线程数的线程池NioEventLoopGroup。然后继续调用父类构造函数该父类的构造函数。

protected MultithreadEventExecutorGroup(int nThreads, Executor executor, EventExecutorChooserFactory chooserFactory, Object... args) {
    this.terminatedChildren = new AtomicInteger();
    this.terminationFuture = new DefaultPromise(GlobalEventExecutor.INSTANCE);
    if (nThreads <= 0) {
        throw new IllegalArgumentException(String.format("nThreads: %d (expected: > 0)", nThreads));
    } else {
        if (executor == null) {
            executor = new ThreadPerTaskExecutor(this.newDefaultThreadFactory());
        }

        this.children = new EventExecutor[nThreads];

        int j;
        for(int i = 0; i < nThreads; ++i) {
            boolean success = false;
            boolean var18 = false;

            try {
                var18 = true;
                this.children[i] = this.newChild((Executor)executor, args);
                success = true;
                var18 = false;
            } catch (Exception var19) {
                throw new IllegalStateException("failed to create a child event loop", var19);
            } finally {
                if (var18) {
                    if (!success) {
                        int j;
                        for(j = 0; j < i; ++j) {
                            this.children[j].shutdownGracefully();
                        }

                        for(j = 0; j < i; ++j) {
                            EventExecutor e = this.children[j];

                            try {
                                while(!e.isTerminated()) {
                                    e.awaitTermination(2147483647L, TimeUnit.SECONDS);
                                }
                            } catch (InterruptedException var20) {
                                Thread.currentThread().interrupt();
                                break;
                            }
                        }
                    }

                }
            }

            if (!success) {
                for(j = 0; j < i; ++j) {
                    this.children[j].shutdownGracefully();
                }

                for(j = 0; j < i; ++j) {
                    EventExecutor e = this.children[j];

                    try {
                        while(!e.isTerminated()) {
                            e.awaitTermination(2147483647L, TimeUnit.SECONDS);
                        }
                    } catch (InterruptedException var22) {
                        Thread.currentThread().interrupt();
                        break;
                    }
                }
            }
        }

        this.chooser = chooserFactory.newChooser(this.children);
        FutureListener<Object> terminationListener = new FutureListener<Object>() {
            public void operationComplete(Future<Object> future) throws Exception {
                if (MultithreadEventExecutorGroup.this.terminatedChildren.incrementAndGet() == MultithreadEventExecutorGroup.this.children.length) {
                    MultithreadEventExecutorGroup.this.terminationFuture.setSuccess((Object)null);
                }

            }
        };
        EventExecutor[] var24 = this.children;
        j = var24.length;

        for(int var26 = 0; var26 < j; ++var26) {
            EventExecutor e = var24[var26];
            e.terminationFuture().addListener(terminationListener);
        }

        Set<EventExecutor> childrenSet = new LinkedHashSet(this.children.length);
        Collections.addAll(childrenSet, this.children);
        this.readonlyChildren = Collections.unmodifiableSet(childrenSet);
    }
}

 这里的构造函数主要做了三件事情;

1.创建线程构造器ThreadPerTaskExecutor

2.使用newChild方法创建child线程组

3.创建线程选择器

 

创建线程构造器

  这里的ThreadPerTaskExecutor相当于是线程池聚合的一个组件,当线程池需要创建线程时,通过该线程构造器去创建一个线程,线程的创建也是工厂模式的一个应用,每次ThreadPerTaskExecutor.execute()都会调用ThreadFactory的newThread()。

public final class ThreadPerTaskExecutor implements Executor {
    private final ThreadFactory threadFactory;

    public ThreadPerTaskExecutor(ThreadFactory threadFactory) {
        if (threadFactory == null) {
            throw new NullPointerException("threadFactory");
        } else {
            this.threadFactory = threadFactory;
        }
    }

    public void execute(Runnable command) {
        this.threadFactory.newThread(command).start();
    }
}

  而这里传入的threadFactory是一个DefaultThreadFactory。

protected ThreadFactory newDefaultThreadFactory() {
    return new DefaultThreadFactory(this.getClass(), 10);
}

 DefaultThreadFactory的构造函数:

public DefaultThreadFactory(Class<?> poolType, int priority) {
    this((Class)poolType, false, priority);
}
public DefaultThreadFactory(String poolName, boolean daemon) {
    this((String)poolName, daemon, 5);
}

public DefaultThreadFactory(Class<?> poolType, int priority) {
    this((Class)poolType, false, priority);
}

public DefaultThreadFactory(String poolName, int priority) {
    this((String)poolName, false, priority);
}

public DefaultThreadFactory(Class<?> poolType, boolean daemon, int priority) {
    this((String)toPoolName(poolType), daemon, priority);
}

private static String toPoolName(Class<?> poolType) {
    if(poolType == null) {
        throw new NullPointerException("poolType");
    } else {
        String poolName = StringUtil.simpleClassName(poolType);
        switch(poolName.length()) {
            case 0:
                return "unknown";
            case 1:
                return poolName.toLowerCase(Locale.US);
            default:
                return Character.isUpperCase(poolName.charAt(0)) && Character.isLowerCase(poolName.charAt(1))?Character.toLowerCase(poolName.charAt(0)) + poolName.substring(1):poolName;
        }
    }
}
public DefaultThreadFactory(String poolName, boolean daemon, int priority) {
    this.nextId = new AtomicInteger();
    if(poolName == null) {
        throw new NullPointerException("poolName");
    } else if(priority >= 1 && priority <= 10) {
        this.prefix = poolName + '-' + poolId.incrementAndGet() + '-';
        this.daemon = daemon;
        this.priority = priority;
    } else {
        throw new IllegalArgumentException("priority: " + priority + " (expected: Thread.MIN_PRIORITY <= priority <= Thread.MAX_PRIORITY)");
    }
}
public Thread newThread(Runnable r) {
    Thread t = this.newThread(new DefaultThreadFactory.DefaultRunnableDecorator(r), this.prefix + this.nextId.incrementAndGet());

    try {
        if(t.isDaemon()) {
            if(!this.daemon) {
                t.setDaemon(false);
            }
        } else if(this.daemon) {
            t.setDaemon(true);
        }

        if(t.getPriority() != this.priority) {
            t.setPriority(this.priority);
        }
    } catch (Exception var4) {
        ;
    }

    return t;
}

  这里传入了当前的类类型NioEventLoopGroup,设置当前线程池的名称为nioEventLoopGroup,线程的优先级为5,然后载调用父类构造函数当前线程池的前缀nioEventLoopGroup-线程池id-。

  当每次进行newThread的时候,会将线程池前缀和当前的线程数传入,所以线程的名称就为nioEventLoopGroup-线程池id-线程数id。

  例如:nioEventLoopGroup-2-1 代表的是第二个线程池的第一个线程。

protected Thread newThread(Runnable r, String name) {
    return new FastThreadLocalThread(r, name);
}

  当调用newThread方法时,其实创建的是一个FastThreadLocalThread对象,netty底层的一个Thread对象,对Thread进行了包装,优化了相关的ThreadLocal操作。

 

通过newChild()方法创建NioEventLoop线程组

  这里的newChild()方法就是创建一个NioEventLoop。

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

   NioEventLoop的构造,要传入父线程池,executor,和provider。每一个NioEventLoop都有一个selector与它进行绑定,为了实现IO多路复用。

NioEventLoop(NioEventLoopGroup parent, Executor executor, SelectorProvider selectorProvider, SelectStrategy strategy, RejectedExecutionHandler rejectedExecutionHandler) {
    super(parent, executor, false, DEFAULT_MAX_PENDING_TASKS, rejectedExecutionHandler);
    if (selectorProvider == null) {
        throw new NullPointerException("selectorProvider");
    } else if (strategy == null) {
        throw new NullPointerException("selectStrategy");
    } else {
        this.provider = selectorProvider;
        NioEventLoop.SelectorTuple selectorTuple = this.openSelector();
        this.selector = selectorTuple.selector;
        this.unwrappedSelector = selectorTuple.unwrappedSelector;
        this.selectStrategy = strategy;
    }
}

   调用父类的构造函数。

protected SingleThreadEventExecutor(EventExecutorGroup parent, Executor executor, boolean addTaskWakesUp, int maxPendingTasks, RejectedExecutionHandler rejectedHandler) {
    super(parent);
    this.threadLock = new Semaphore(0);
    this.shutdownHooks = new LinkedHashSet();
    this.state = 1;
    this.terminationFuture = new DefaultPromise(GlobalEventExecutor.INSTANCE);
    this.addTaskWakesUp = addTaskWakesUp;
    this.maxPendingTasks = Math.max(16, maxPendingTasks);
    this.executor = (Executor)ObjectUtil.checkNotNull(executor, "executor");
    this.taskQueue = this.newTaskQueue(this.maxPendingTasks);
    this.rejectedExecutionHandler = (RejectedExecutionHandler)ObjectUtil.checkNotNull(rejectedHandler, "rejectedHandler");
}

  父类创建任务队列,如果不是NioEventLoop对应的线程,当是外部线程时,就将任务放入任务队列,否则使用线程执行任务。这里的任务队列是LinkedBlockingQueue

protected Queue<Runnable> newTaskQueue() {
    return new LinkedBlockingQueue();
}

  NioEventLoop的主要组件就是selector,taskqueue,thread,selector用于IO多路复用,使用selector才能使得一个线程能处理多个连接(channel的事件),而thread就是存储当前NioEventLoop的线程,如果不在当前线程中,那么就将任务提交到任务队列中taskqueue。

 

创建线程选择器

  线程选择器是对应NioEventLoopGroup.next()方法,每当有一个新的连接进入的时候,NioEventLoopGroup要选择一个NioEventLoop和新连接进行绑定。

 

  在创建线程选择器的时候会判断当前线程池的个数是不是2的幂次方,如果是就创建一个PowerOfTwoEventExecutorChooser,否则就创建一个GenericEventExecutorChooser。

if(isPowerOfTwo(this.children.length)) {
    this.chooser = new MultithreadEventExecutorGroup.PowerOfTwoEventExecutorChooser(null);
} else {
    this.chooser = new MultithreadEventExecutorGroup.GenericEventExecutorChooser(null);
}

  普通的线程选择器:

private final class GenericEventExecutorChooser implements MultithreadEventExecutorGroup.EventExecutorChooser {
    private GenericEventExecutorChooser() {
    }

    public EventExecutor next() {
        return MultithreadEventExecutorGroup.this.children[Math.abs(MultithreadEventExecutorGroup.this.childIndex.getAndIncrement() % MultithreadEventExecutorGroup.this.children.length)];
    }
}

  二的幂次方线程选择器:

private final class PowerOfTwoEventExecutorChooser implements MultithreadEventExecutorGroup.EventExecutorChooser {
    private PowerOfTwoEventExecutorChooser() {
    }

    public EventExecutor next() {
        return MultithreadEventExecutorGroup.this.children[MultithreadEventExecutorGroup.this.childIndex.getAndIncrement() & MultithreadEventExecutorGroup.this.children.length - 1];
    }
}

  但满足线程数是2的幂次方时,采用&操作来优化,&比%要高效很多。

转载于:https://www.cnblogs.com/xiaobaituyun/p/10799786.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值