才出现了一些例如Netty的优秀的开发源框架
netty官方网站
netty分为三大模块
可以直接在项目中添加 maven 依赖或者gradle
io.netty
netty-all
4.1.68.Final
在netty-all中包含的这所有的模块,包括buffer channel handler 等等核心,根据需要选择 不同 maven 依赖
这里面包含了netty的各个部分。
使用一个netty作为一个例子将例子启动起来
public class NettyStarter {
public static void main(String[] args) throws InterruptedException {
// 主线程组 处理客户连接
NioEventLoopGroup mainGroup = new NioEventLoopGroup(1);
// 工人线程组,处理客户端的请求 读取 和写入
NioEventLoopGroup subGroup = new NioEventLoopGroup();
// 创建启动器, 并配置
ServerBootstrap boostrap = new ServerBootstrap();
boostrap.group(mainGroup, subGroup).option(ChannelOption.SO_BACKLOG, 1024).channel(NioServerSocketChannel.class)
.handler(new LoggingHandler(LogLevel.INFO));
// 绑定端口并使用
Channel channel = boostrap.bind(8081).sync().channel();
// 监听channeal 释放并 停止 线程组
channel.closeFuture().addListeners(future -> {
mainGroup.shutdownGracefully();
subGroup.shutdownGracefully();
});
}
}
并且netty是可以使用bio的程序需要修改 线程组,这是netty提供的类,这个修改也是非常简单的
// 主线程组 处理客户都安连接
OioEventLoopGroup mainGroup = new OioEventLoopGroup(1);
// 工人线程组,处理客户端的请求 读取 和写入
OioEventLoopGroup subGroup = new OioEventLoopGroup();
至于为什么 要加主线程组以及子线程组,可以看一下下面篇博客
Reactor网络编程模型解析
netty 在github源代码
netty github的源代码及例子实现
请求流程
NioEventLoopGroup subGroup = new NioEventLoopGroup();
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 MultithreadEventLoopGroup(int nThreads, Executor executor, Object... args) {
super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, executor, args);
}
1. 首先做了创建线程执行器 和 事件执行器数组
protected MultithreadEventExecutorGroup(int nThreads, Executor executor,
EventExecutorChooserFactory chooserFactory, Object... args) {
checkPositive(nThreads, "nThreads");
//线程执行器 ,如果在创建eventLoopGroup时没有指定,则使用netty提供的默认执行器
if (executor == null) {
executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
}
//创建 事件执行器的数组
children = new EventExecutor[nThreads];
//创建事件轮询器
for (int i = 0; i < nThreads; i ++) {
boolean success = false;
try {
children[i] = newChild(executor, args);
success = true;
} catch (Exception e) {
// TODO: 创建失败
throw new IllegalStateException("failed to create a child event loop", e);
} finally {
//等等就省略掉
}
}
}
从这个newChild方法上追寻下去 是由NioEventLoopGroup里面实现 这里使用了模板模式 创建NioEventLoop其实上面做了一些操作,和我们初始化并不是特别大的关联就不看了
在NioEventLoop初始化就能看到里面做的一些事情了
包括比较重要的newTaskQueue 选择提供器 和 selector provider 提供器,如果不太清楚的话可以看一下 nio 中selector.open()方法也是通过provider方法 去创建selector对象
public static Selector open() throws IOException {
return SelectorProvider.provider().openSelector();
}
2.继续创建一个选择器
//创建选择器
chooser = chooserFactory.newChooser(children);
这个选择器的作用用于连接过来时选择不同的工作线程 也就是NioEventLoop
从MultithreadEventLoopGroup的实现来看出 netty包括下面几种实现创建evntLoop事件驱动器
该方法主要用于选择那个工作子线程进行读取 数据
@Override
public ChannelFuture register(Channel channel) {
return next().register(channel);
}
而这里的next 方法就是刚才 创建选择器的 方法
@Override
public EventExecutorChooser newChooser(EventExecutor[] executors) {
if (isPowerOfTwo(executors.length)) {
return new PowerOfTwoEventExecutorChooser(executors);
} else {
return new GenericEventExecutorChooser(executors);
}
}
随便点DefaultEventExecutorChooserFactory 这个进去就能很容易看到选择线程的方式
public EventExecutor next() {
return executors[Math.abs(idx.getAndIncrement() % executors.length)];
}
public final class NioEventLoop extends SingleThreadEventLoop {
public abstract class SingleThreadEventLoop extends SingleThreadEventExecutor implements EventLoop {
private void doStartThread() {
assert thread == null;
executor.execute(new Runnable() {
@Override
public void run() {
thread = Thread.currentThread();
if (interrupted) {
thread.interrupt();
}
boolean success = false;
updateLastExecutionTime();
try {
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_DO
这里做的就是不断的死循环,队列里面的方法。