Netty 02 | 源码分析

基于Netty3 摘抄了核心源码。
Netty 是如何工作的?
因为代码中没有异步的代码。那非阻塞是如何实现的?

一个 NIO 是不是只能有一个 selector ?

可以有多个 selector

selector 是不是只能注册一个 ServerSocketChannel?

可以注册多个
在这里插入图片描述

  • 目录结构
    目录结构

初始化服务

Start

//初始化线程
		NioSelectorRunnablePool nioSelectorRunnablePool = new NioSelectorRunnablePool(Executors.newCachedThreadPool(), Executors.newCachedThreadPool());
		
		//获取服务类 
		ServerBootstrap bootstrap = new ServerBootstrap(nioSelectorRunnablePool);
		
		//绑定端口
		//初始化 Channel
		//线程池 获取 boss select
		//selverChanner 注册到 selector , key 为 accept 状态
		bootstrap.bind(new InetSocketAddress(10101));
		
		System.out.println("start");
  1. init 线程池
    boss 线程池
    woker 线程池
    每个线程一个 selector

  2. selector implements Runnable
    1个selector 有 1个Queue taskQueue
    每个 selector 都公用 boss pool or worker pool

  3. 每一个 selector 获取 Selector 并启动线程 ,在 AbstractNioSelector 中执行 run 方法。

/**
	 * 获取selector并启动线程
	 */
	private void openSelector() {
		try {
			this.selector = Selector.open();
		} catch (IOException e) {
			throw new RuntimeException("Failed to create a selector.");
		}
		executor.execute(this);
	}
	run :
while (true) {
			try {
				wakenUp.set(false);

				select(selector);

				processTaskQueue();

				process(selector);
			} catch (Exception e) {
				// ignore
			}
		}

Boss or Worker 注册不同 Selector 的特有接口

public interface Boss {
	
	/**
	 * 加入一个新的ServerSocket
	 * @param serverChannel
	 */
	public void registerAcceptChannelTask(ServerSocketChannel serverChannel);
}

NioSelectorRunnablePool

/**
	 * boss线程数组
	 */
	private final AtomicInteger bossIndex = new AtomicInteger();
	private Boss[] bosses;

	/**
	 * worker线程数组
	 */
	private final AtomicInteger workerIndex = new AtomicInteger();
	private Worker[] workeres;
  1. 初始化线程池
  2. init boss 创建NIOServerBoss
private void initBoss(Executor boss, int count) {
		this.bosses = new NioServerBoss[count];
		for (int i = 0; i < bosses.length; i++) {
			bosses[i] = new NioServerBoss(boss, "boss thread " + (i+1), this);
		}
	}
  1. initWorker 创建
private void initWorker(Executor worker, int count) {
		this.workeres = new NioServerWorker[count];
		for (int i = 0; i < workeres.length; i++) {
			workeres[i] = new NioServerWorker(worker, "worker thread " + (i+1), this);
		}
	}
  1. 注册并激活selector
    当 boss 加入一个新的SeverSocket 时 //负责监听端口 channel
    当 worker channel 加入 selector 时 // 负责处理具体的 事件 channel
/**
	 * 注册一个任务并激活selector
	 * 
	 * @param task
	 */
	protected final void registerTask(Runnable task) {
		taskQueue.add(task);

		Selector selector = this.selector;

		if (selector != null) {
			//if wakeUp 是false那么 update为 true
			//False return indicates that the actual value was not equal to the expected value.
			if (wakenUp.compareAndSet(false, true)) {
				selector.wakeup();//唤醒阻塞的 selector
			}
		} else {
			taskQueue.remove(task);
		}
	}

ServerBootstrap

服务类,绑定端口

NioServerBoss

NioServerBoss extends AbstractNioSelector implements Boss

NioServerWorker

extends AbstractNioSelector implements Worker

AbstractNioSelector implements Runnable 最顶层的selector

  • 初始化
  • 每个线程都有 selector 的能力
	AbstractNioSelector(Executor executor, String threadName, NioSelectorRunnablePool selectorRunnablePool) {
		this.executor = executor;
		this.threadName = threadName;
		this.selectorRunnablePool = selectorRunnablePool;
		openSelector();
	}
	
	/**
	 * 获取selector并启动线程
	 */
	private void openSelector()  {
		try {
			this.selector = Selector.open(); 
		} catch (IOException e) {
			throw new RuntimeException("Failed to create a selector.");
		}
		executor.execute(this);//执行当前线程对象,运行下面的 run方法
	}
  • 核心!!!!!!!
	@Override
	public void run() {
		
		Thread.currentThread().setName(this.threadName);

		while (true) {
			try {
			    //设置select 阻塞状态,当 registerTask 方法执行时醒来,处理。
				wakenUp.set(false); 
				 
				//抽象方法
				//boss 选择阻塞 自定义
				//worker 选择阻塞500ms 自定义
				select(selector); 
				
				//执行任务队列中 Runnable 对象的run ,注册 channel到 boss or worker 等待处理的对象。
				processTaskQueue();
                
                //处理 selector
                //boss 非阻塞接收事件,然后 register 到 worker 的队列。
                //worker 具体处理事件,与返回事件
				process(selector);
			} catch (Exception e) {
				// ignore
			}
		}
	}
bossworker
在这里插入图片描述在这里插入图片描述
  • wakeup selector,防止其阻塞下一步程序
/**
	 * 注册一个任务并激活selector
	 * 
	 * @param task
	 */
	protected final void registerTask(Runnable task) {
		taskQueue.add(task);

		Selector selector = this.selector;

		if (selector != null) {
			//if wakeUp 是false那么 update为 true
			//False return indicates that the actual value was not equal to the expected value.
			if (wakenUp.compareAndSet(false, true)) {
				selector.wakeup();//唤醒阻塞的 selector
			}
		} else {
			taskQueue.remove(task);
		}
	}

结论

  • NIO 如何提高的效率?
    通过 selector 。在 1个线程中1个 selector 可以注册多个 serversocketchannel 对多个client进行监听。

源码DEMO

https://github.com/GggggitHub/Netty01

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值