1. package com.cn;
  2.  
  3. import java.io.IOException;
  4. import java.nio.channels.Selector;
  5. import java.util.Queue;
  6. import java.util.concurrent.ConcurrentLinkedQueue;
  7. import java.util.concurrent.Executor;
  8. import java.util.concurrent.atomic.AtomicBoolean;
  9.  
  10. import com.cn.pool.NioSelectorRunnablePool;
  11.  
  12. /**
  13. * 抽象selector线程基类
  14. */
  15. public abstract class AbstractNioSelector implements Runnable {
  16.  
  17. /**
  18. * 线程池
  19. */
  20. private final Executor executor;
  21.  
  22. /**
  23. * 选择器
  24. */
  25. protected Selector selector;
  26.  
  27. /**
  28. * 选择器wakenUp状态标记
  29. */
  30. protected final AtomicBoolean wakenUp = new AtomicBoolean();
  31.  
  32. /**
  33. * 线程安全任务队列
  34. */
  35. private final Queue<Runnable> taskQueue = new ConcurrentLinkedQueue<Runnable>();
  36.  
  37. /**
  38. * 线程名称
  39. */
  40. private String threadName;
  41.  
  42. /**
  43. * 线程池管理对象
  44. */
  45. protected NioSelectorRunnablePool selectorRunnablePool;
  46.  
  47. AbstractNioSelector(Executor executor, String threadName, NioSelectorRunnablePool selectorRunnablePool) {
  48. this.executor = executor;
  49. this.threadName = threadName;
  50. this.selectorRunnablePool = selectorRunnablePool;
  51. openSelector();
  52. }
  53.  
  54. /**
  55. * 获取selector并启动线程,一个线程拥有了select才能为多个客服服务。
  56. */
  57. private void openSelector() {
  58. try {
  59. this.selector = Selector.open();
  60. } catch (IOException e) {
  61. throw new RuntimeException("Failed to create a selector.");
  62. }
  63. executor.execute(this);//像线程池中加入一个任务,并执行任务的run方法。运行当前任务,执行run方法。从线程池拿出一个线程执行这个任务。
  64. }
  65.  
  66. @Override
  67. public void run() {
  68.  
  69. Thread.currentThread().setName(this.threadName);//给当前线程付一个名字
  70.  
  71. while (true) {
  72. try {
  73. wakenUp.set(false);
  74.  
  75. select(selector);//接口,执行NioServerBoss或者NioServerWorker的select方法
  76.  
  77. processTaskQueue();//执行完任务队列里面的任务
  78.  
  79. process(selector);//接口,执行NioServerBoss或者NioServerWorker的process方法
  80. } catch (Exception e) {
  81. // ignore
  82. }
  83. }
  84.  
  85. }
  86.  
  87. /**
  88. * 注册一个任务并激活selector
  89. *
  90. * @param task
  91. */
  92. protected final void registerTask(Runnable task) {
  93. taskQueue.add(task);
  94.  
  95. Selector selector = this.selector;
  96.  
  97. if (selector != null) {
  98. if (wakenUp.compareAndSet(false, true)) {//wakenUp是不是false,是false就置为true,
  99. selector.wakeup();
  100. }
  101. } else {
  102. taskQueue.remove(task);
  103. }
  104. }
  105.  
  106. /**
  107. * 执行队列里的任务
  108. */
  109. private void processTaskQueue() {
  110. for (;;) {
  111. final Runnable task = taskQueue.poll();
  112. if (task == null) {
  113. break;
  114. }
  115. task.run();//task是runnable元素
  116. }
  117. }
  118.  
  119. /**
  120. * 获取线程管理对象
  121. * @return
  122. */
  123. public NioSelectorRunnablePool getSelectorRunnablePool() {
  124. return selectorRunnablePool;
  125. }
  126.  
  127. /**
  128. * select抽象方法
  129. 子类有重写
  130. */
  131. protected abstract int select(Selector selector) throws IOException;
  132.  
  133. /**
  134. * selector的业务处理
  135. 子类有重写
  136. */
  137. protected abstract void process(Selector selector) throws IOException;
  138.  
  139. }
  1. package com.cn;
  2.  
  3. import java.io.IOException;
  4. import java.nio.channels.ClosedChannelException;
  5. import java.nio.channels.SelectionKey;
  6. import java.nio.channels.Selector;
  7. import java.nio.channels.ServerSocketChannel;
  8. import java.nio.channels.SocketChannel;
  9. import java.util.Iterator;
  10. import java.util.Set;
  11. import java.util.concurrent.Executor;
  12.  
  13. import com.cn.pool.Boss;
  14. import com.cn.pool.NioSelectorRunnablePool;
  15. import com.cn.pool.Worker;
  16. /**
  17. * boss实现类,每一个NioServerBoss再一个线程里面
  18. */
  19. public class NioServerBoss extends AbstractNioSelector implements Boss{
  20.  
  21. public NioServerBoss(Executor executor, String threadName, NioSelectorRunnablePool selectorRunnablePool) {
  22. super(executor, threadName, selectorRunnablePool);
  23. }
  24.  
  25. @Override
  26. protected void process(Selector selector) throws IOException {
  27. Set<SelectionKey> selectedKeys = selector.selectedKeys();
  28. if (selectedKeys.isEmpty()) {
  29. return;
  30. }
  31.  
  32. for (Iterator<SelectionKey> i = selectedKeys.iterator(); i.hasNext();) {
  33. SelectionKey key = i.next();
  34. i.remove();
  35. ServerSocketChannel server = (ServerSocketChannel) key.channel();
  36. // 新客户端
  37. SocketChannel channel = server.accept();
  38. // 设置为非阻塞
  39. channel.configureBlocking(false);
  40. // 获取一个worker
  41. Worker nextworker = getSelectorRunnablePool().nextWorker();//通过线程管理对象获取一个worker(runnable任务对象),
  42. // 注册新客户端接入任务,将新的连接请求交给worker。
  43. nextworker.registerNewChannelTask(channel);//往别的任务队列里面加任务
  44. //安卓里面,子线程不能改变UI,要改变就要向主线程的任务队列里面加任务。
  45.  
  46. System.out.println("新客户端链接");
  47. }
  48. }
  49.  
  50. public void registerAcceptChannelTask(final ServerSocketChannel serverChannel){
  51. final Selector selector = this.selector;
  52. registerTask(new Runnable() {
  53. @Override
  54. public void run() {
  55. try {
  56. //注册serverChannel到selector
  57. serverChannel.register(selector, SelectionKey.OP_ACCEPT);
  58. } catch (ClosedChannelException e) {
  59. e.printStackTrace();
  60. }
  61. }
  62. });
  63. }
  64.  
  65. @Override
  66. protected int select(Selector selector) throws IOException {
  67. return selector.select();
  68. }
  69. }
  1. package com.cn;
  2.  
  3. import java.io.IOException;
  4. import java.nio.ByteBuffer;
  5. import java.nio.channels.ClosedChannelException;
  6. import java.nio.channels.SelectionKey;
  7. import java.nio.channels.Selector;
  8. import java.nio.channels.SocketChannel;
  9. import java.util.Iterator;
  10. import java.util.Set;
  11. import java.util.concurrent.Executor;
  12.  
  13. import com.cn.pool.NioSelectorRunnablePool;
  14. import com.cn.pool.Worker;
  15. /**
  16. * worker实现类,每一个NioServerWorker再一个线程里面
  17. */
  18. public class NioServerWorker extends AbstractNioSelector implements Worker{
  19.  
  20. public NioServerWorker(Executor executor, String threadName, NioSelectorRunnablePool selectorRunnablePool) {
  21. super(executor, threadName, selectorRunnablePool);
  22. }
  23.  
  24. @Override
  25. protected void process(Selector selector) throws IOException {
  26. Set<SelectionKey> selectedKeys = selector.selectedKeys();
  27. if (selectedKeys.isEmpty()) {
  28. return;
  29. }
  30. Iterator<SelectionKey> ite = this.selector.selectedKeys().iterator();
  31. while (ite.hasNext()) {
  32. SelectionKey key = (SelectionKey) ite.next();
  33. // 移除,防止重复处理
  34. ite.remove();
  35.  
  36. // 得到事件发生的Socket通道
  37. SocketChannel channel = (SocketChannel) key.channel();
  38.  
  39. // 数据总长度
  40. int ret = 0;
  41. boolean failure = true;
  42. ByteBuffer buffer = ByteBuffer.allocate(1024);
  43. //读取数据
  44. try {
  45. ret = channel.read(buffer);
  46. failure = false;
  47. } catch (Exception e) {
  48. // ignore
  49. }
  50. //判断是否连接已断开
  51. if (ret <= 0 || failure) {
  52. key.cancel();
  53. System.out.println("客户端断开连接");
  54. }else{
  55. System.out.println("收到数据:" + new String(buffer.array()));
  56.  
  57. //回写数据
  58. ByteBuffer outBuffer = ByteBuffer.wrap("收到\n".getBytes());
  59. channel.write(outBuffer);// 将消息回送给客户端
  60. }
  61. }
  62. }
  63.  
  64. /**
  65. * 加入一个新的socket客户端
  66. */
  67. public void registerNewChannelTask(final SocketChannel channel){
  68. final Selector selector = this.selector;
  69. registerTask(new Runnable() {
  70. @Override
  71. public void run() {
  72. try {
  73. //将客户端注册到selector中
  74. channel.register(selector, SelectionKey.OP_READ);
  75. } catch (ClosedChannelException e) {
  76. e.printStackTrace();
  77. }
  78. }
  79. });
  80. }
  81.  
  82. @Override
  83. protected int select(Selector selector) throws IOException {
  84. return selector.select(60000);
  85. }
  86.  
  87. }
  1. package com.cn;
  2.  
  3. import java.net.SocketAddress;
  4. import java.nio.channels.ServerSocketChannel;
  5.  
  6. import com.cn.pool.Boss;
  7. import com.cn.pool.NioSelectorRunnablePool;
  8. /**
  9. * 服务类
  10. */
  11. public class ServerBootstrap {
  12.  
  13. private NioSelectorRunnablePool selectorRunnablePool;
  14.  
  15. public ServerBootstrap(NioSelectorRunnablePool selectorRunnablePool) {
  16. this.selectorRunnablePool = selectorRunnablePool;
  17. }
  18.  
  19. /**
  20. * 监听端口
  21. * @param localAddress
  22. */
  23. public void bind(final SocketAddress localAddress){
  24. try {
  25. // 获得一个ServerSocket通道
  26. ServerSocketChannel serverChannel = ServerSocketChannel.open();
  27. // 设置通道为非阻塞
  28. serverChannel.configureBlocking(false);
  29. // 将该通道对应的ServerSocket绑定到port端口
  30. serverChannel.socket().bind(localAddress);
  31.  
  32. //获取一个boss线程
  33. Boss nextBoss = selectorRunnablePool.nextBoss();
  34. //向boss注册一个ServerSocket通道
  35. nextBoss.registerAcceptChannelTask(serverChannel);
  36. } catch (Exception e) {
  37. e.printStackTrace();
  38. }
  39. }
  40. }
  1. package com.cn;
  2.  
  3. import java.net.InetSocketAddress;
  4. import java.util.concurrent.Executors;
  5. import com.cn.pool.NioSelectorRunnablePool;
  6. /**
  7. * 启动函数
  8. */
  9. public class Start {
  10.  
  11. public static void main(String[] args) {
  12.  
  13. //管理线程池的,初始化2个线程池,一个boss一个work,
  14. NioSelectorRunnablePool nioSelectorRunnablePool = new NioSelectorRunnablePool(Executors.newCachedThreadPool(), Executors.newCachedThreadPool());
  15.  
  16. //获取服务类
  17. ServerBootstrap bootstrap = new ServerBootstrap(nioSelectorRunnablePool);
  18.  
  19. //绑定端口
  20. bootstrap.bind(new InetSocketAddress(10101));
  21.  
  22. System.out.println("start");
  23. }
  24.  
  25. }
  1. package com.cn.pool;
  2.  
  3. import java.nio.channels.ServerSocketChannel;
  4. /**
  5. * boss接口
  6. */
  7. public interface Boss {
  8.  
  9. /**
  10. * 加入一个新的ServerSocket,监听连接
  11. */
  12. public void registerAcceptChannelTask(ServerSocketChannel serverChannel);
  13. }
  1. package com.cn.pool;
  2.  
  3. import java.util.concurrent.Executor;
  4. import java.util.concurrent.ExecutorService;
  5. import java.util.concurrent.Executors;
  6. import java.util.concurrent.atomic.AtomicInteger;
  7. import com.cn.NioServerBoss;
  8. import com.cn.NioServerWorker;
  9. /**
  10. * selector线程管理者
  11. *
  12. * 线程池是有多个线程,每个线程里面有一个任务队列,线程run的时候会从任务队列取一个任务出来,执行任务的run方法,
  13. 队列里面没有任务就阻塞等待新的任务进来。
  14. */
  15. public class NioSelectorRunnablePool {
  16.  
  17. /**
  18. * boss任务数组,boss用来监听端口的,
  19. */
  20. private final AtomicInteger bossIndex = new AtomicInteger();
  21. private Boss[] bosses;
  22.  
  23. /**
  24. * worker任务数组,用来处理事件的,
  25. */
  26. private final AtomicInteger workerIndex = new AtomicInteger();
  27. private Worker[] workeres;
  28.  
  29. //boss和worker是一个线程池
  30. public NioSelectorRunnablePool(Executor boss, Executor worker) {
  31. initBoss(boss, 1);//boss是一个线程池。
  32. initWorker(worker, Runtime.getRuntime().availableProcessors() * 2);
  33. }
  34.  
  35. /**
  36. * 初始化boss线程池的runable任务数组
  37. * @param boss
  38. * @param count
  39. */
  40. private void initBoss(Executor boss, int count) {
  41. this.bosses = new NioServerBoss[count];
  42. //this.bosses是一个数组,里面是一个个的NioServerBoss,
  43. //NioServerBoss是runnable任务对象。runnable对象里面有线程池、选择器、线程名、线程管理者。
  44. //executor.execute(this);通过NioServerBoss里面的线程池把任务对象NioServerBoss自己运行起来。
  45. //所有的NioServerBoss任务对象都是通过boss线程池来调度的。
  46. for (int i = 0; i < bosses.length; i++) {
  47. bosses[i] = new NioServerBoss(boss, "boss thread " + (i+1), this);//this是NioSelectorRunnablePool线程池管理者。
  48. //boss thread 是任务runable的名字
  49. }
  50. }
  51.  
  52. /**
  53. * 初始化worker线程池的runable任务数组
  54. * @param worker
  55. * @param count
  56. */
  57. private void initWorker(Executor worker, int count) {
  58. this.workeres = new NioServerWorker[2/*count*/];
  59. for (int i = 0; i < workeres.length; i++) {
  60. //所有的NioServerWorker任务对象都是通过worker线程池来调度的。
  61. workeres[i] = new NioServerWorker(worker, "worker thread " + (i+1), this);
  62. }
  63. //boss线程池里面有8个NioServerBoss.runable对象(8个大任务,开了8个线程),
  64. //每一个NioServerWorker再一个线程里面。8个NioServerBoss.runable对象一开始就去run,
  65. //每个NioServerBoss.runable对象里面有一个任务队列taskQueue,队列里面是一个个的Runnable对象。
  66.  
  67. /*
  68. public static void main(String[] args) {
  69. //创建一个线程池,可回收的,没任务就回收了。newCachedThreadPool可以很大。60秒没任务就回收。
  70. ExecutorService pool = Executors.newCachedThreadPool();//线程池
  71. for(int i = 1; i < 5; i++){//4个任务,一个任务就是一个Runnable
  72. pool.execute(new Runnable() {//没有返回值
  73. @Override
  74. public void run() {
  75. try {
  76. Thread.sleep(5);
  77. } catch (InterruptedException e) {
  78. e.printStackTrace();
  79. }
  80. System.out.println("thread name: " + Thread.currentThread().getName());
  81.  
  82. }
  83. });
  84. try {
  85. Thread.sleep(5);
  86. } catch (InterruptedException e) {
  87. e.printStackTrace();
  88. }
  89. }
  90. pool.shutdown();//任务执行完就关了。
  91. /*thread name: pool-1-thread-1
  92. thread name: pool-1-thread-2
  93. thread name: pool-1-thread-1
  94. thread name: pool-1-thread-2 线程执行完了会回收,不一定开4个线程*/
  95. }
  96.  
  97. /**
  98. * 获取一个worker的runable任务,给每个work平均分配
  99. */
  100. public Worker nextWorker() {
  101. return workeres[Math.abs(workerIndex.getAndIncrement() % workeres.length)];
  102. }
  103.  
  104. /**
  105. * 获取一个boss的runable任务
  106. */
  107. public Boss nextBoss() {
  108. return bosses[Math.abs(bossIndex.getAndIncrement() % bosses.length)];
  109. }
  110. }
  1. package com.cn.pool;
  2.  
  3. import java.nio.channels.SocketChannel;
  4. /**
  5. * worker接口
  6. */
  7. public interface Worker {
  8.  
  9. /**
  10. * 加入一个新的客户端会话,监听客户端的处理
  11. */
  12. public void registerNewChannelTask(SocketChannel channel);
  13.  
  14. }

netty12---线程池简单源码的更多相关文章

  1. 深入浅出Java线程池:源码篇

    前言 在上一篇文章深入浅出Java线程池:理论篇中,已经介绍了什么是线程池以及基本的使用.(本来写作的思路是使用篇,但经网友建议后,感觉改为理论篇会更加合适).本文则深入线程池的源码,主要是介绍Thr ...

  2. Java并发包源码学习系列:线程池ScheduledThreadPoolExecutor源码解析

    目录 ScheduledThreadPoolExecutor概述 类图结构 ScheduledExecutorService ScheduledFutureTask FutureTask schedu ...

  3. java线程池ThreadPoolExector源码分析

    java线程池ThreadPoolExector源码分析 今天研究了下ThreadPoolExector源码,大致上总结了以下几点跟大家分享下: 一.ThreadPoolExector几个主要变量 先 ...

  4. linux线程池thrmgr源码解析

    linux线程池thrmgr源码解析 1         thrmgr线程池的作用 thrmgr线程池的作用是提高程序的并发处理能力,在多CPU的服务器上运行程序,可以并发执行多个任务. 2      ...

  5. 一个python线程池的源码解析

    python为了方便人们编程高度封装了很多东西,比如进程里的进程池,大大方便了人们编程的效率,但是默认却没有线程池,本人前段时间整理出一个线程池,并进行了简单的解析和注释,本人水平有限,如有错误希望高 ...

  6. [转载] Java线程池框架源码分析

    转载自http://www.linuxidc.com/Linux/2014-11/108791.htm 相关类Executor,Executors,AbstractExecutorService,Ex ...

  7. 线程池ThreadPoolExecutor源码解读研究(JDK1.8)

    一.什么是线程池 为什么要使用线程池?在多线程并发开发中,线程的数量较多,且每个线程执行一定的时间后就结束了,下一个线程任务到来还需要重新创建线程,这样线程数量特别庞大的时候,频繁的创建线程和销毁线程 ...

  8. 线程池ThreadPoolExecutor源码分析

    在阿里编程规约中关于线程池强制了两点,如下: [强制]线程资源必须通过线程池提供,不允许在应用中自行显式创建线程.说明:使用线程池的好处是减少在创建和销毁线程上所消耗的时间以及系统资源的开销,解决资源 ...

  9. ThreadPoolExecutor 线程池的源码解析

    1.背景介绍 上一篇从整体上介绍了Executor接口,从上一篇我们知道了Executor框架的最顶层实现是ThreadPoolExecutor类,Executors工厂类中提供的newSchedul ...

  10. 【Java并发编程】21、线程池ThreadPoolExecutor源码解析

    一.前言 JUC这部分还有线程池这一块没有分析,需要抓紧时间分析,下面开始ThreadPoolExecutor,其是线程池的基础,分析完了这个类会简化之后的分析,线程池可以解决两个不同问题:由于减少了 ...

随机推荐

  1. 第四篇:使用 CUBLAS 库给矩阵运算提速

    前言 编写 CUDA 程序真心不是个简单的事儿,调试也不方便,很费时.那么有没有一些现成的 CUDA 库来调用呢? 答案是有的,如 CUBLAS 就是 CUDA 专门用来解决线性代数运算的库. 本文将 ...

  2. Django学习笔记第七篇--实战练习三--关于更有层级的url请求、404错误以及其他响应函数

    一.关于更有层级的URL: 可以实现每一个APP一个子URL目录,例如app1的所有操作都在http://www.localhost1.com:5443/app1/xxxx 在工程主文件夹下的工程同名 ...

  3. 常用SEO优化技巧

    SEO是指搜索引擎优化 搜索引擎优化是一种利用搜索引擎的搜索规则来提高目前网站在有关搜索引擎内的自然排名的方式.SEO的目的理解是:为网站提供生态式的自我营销解决方案,让网站在行业内占据领先地位,从而 ...

  4. IDEA整合日志框架Log4j2+Slf4j详细配置过程

    日志框架这么多,他们之间到底是什么关系呢?笼统的讲就是slf4j是一系列的日志接口,而log4j2.logback是具体实现了接口功能的日志框架.现在的主流日志接口都使用slf4j,而日志的实现就见仁 ...

  5. Java基础之MySQL数据库与JDBC

    一.数据库 DBMS         数据库管理系统 是由多个程序构成的专门用来管理大量数据的计算机系统 Server       提供数据存储.检索.计算等服务的网络程序+系统服务 Notifier ...

  6. wxshop_my移动端前端开发项目

    **************************************************************************************************** ...

  7. CentOS中制作本地yum源

    1.光盘指向镜像 2.将镜像挂载到某个目录 mkdir /mnt/cdrom mount -t iso9660 -o ro /dev/cdrom /mnt/cdrom 3.修改本机上的YUM源配置文件 ...

  8. Web测试系列之测试工具

    一Web功能测试工具MAXQ MAXQ是开源的Web功能测试工具. MAXQ是开源的Web功能测试工具.他的特点:1)简单易学;2)是一个轻量级的Web功能测试工具;3)可以自动录制WebBrowse ...

  9. 启动windows服务的bat文件编写格式

    1.bat文件需要和bin文件内容放在一起 启动服务的bat文件如下: sc create 邮件服务 binPath= "%~dp0可执行文件名称.exe" start= auto ...

  10. SOCKS5的出现缓解了各种具体协议需要专门设计代理协议的困难局面

    socks5_百度百科 https://baike.baidu.com/item/socks5/8915011?fr=aladdin 如果您的机器具有一个合法的 Internet IP 地址, 或者您 ...