`

Netty学习之旅------线程模型前置篇Reactor反应堆设计模式实现(基于java.nio)

阅读更多

1、Reactor反应堆设计模式

1.1、单线程模型


                          单线程模型Reactor(此图来源与网络)

下面以Java nio为基础,实现Reactor模型。

Nio服务端代码:

 

[java] view plain copy
 
print?
  1. package threadmode.r1;  
  2.   
  3. import java.io.IOException;  
  4. import java.net.InetSocketAddress;  
  5. import java.nio.ByteBuffer;  
  6. import java.nio.channels.SelectionKey;  
  7. import java.nio.channels.Selector;  
  8. import java.nio.channels.ServerSocketChannel;  
  9. import java.nio.channels.SocketChannel;  
  10. import java.util.Iterator;  
  11. import java.util.Set;  
  12.   
  13. /** 
  14.  * Nio服务器, 
  15.  * 本例主要用来增加对 Ractor 线程模型的理解,不会考虑半包等网络问题 
  16.  *  
  17.  * 例子程序的功能:服务器接受客户端的请求数据,然后在后面再追加 (hello,服务器收到了你的信息。) 
  18.  * @author dingwei2 
  19.  *  
  20.  *  
  21.  *  
  22.  *  
  23.  * 
  24.  */  
  25. public class NioServer {  
  26.   
  27.     public static void main(String[] args) {  
  28.         // TODO Auto-generated method stub  
  29.           
  30.         //   
  31.         (new Thread(new Reactor())).start();  
  32.   
  33.     }  
  34.       
  35.     /** 
  36.      * Reactor模型,反应堆 
  37.      * @author dingwei2 
  38.      * 
  39.      */  
  40.     private static final class Reactor implements Runnable {  
  41.           
  42. //      private static final ConcurrentHashMap<SocketChannel, ByteBuffer> waitSendData   
  43. //                                          = new ConcurrentHashMap<SocketChannel, ByteBuffer>();  
  44.           
  45.         private static final byte[] b = "hello,服务器收到了你的信息。".getBytes();  
  46.   
  47.         public void run() {  
  48.             // TODO Auto-generated method stub  
  49.             System.out.println("服务端启动成功,等待客户端接入");  
  50.             ServerSocketChannel ssc = null;  
  51.             Selector selector = null;  
  52.             try {  
  53.                 ssc = ServerSocketChannel.open();  
  54.                 ssc.configureBlocking(false);  
  55.                 ssc.bind(new InetSocketAddress("127.0.0.1"9080));  
  56.                   
  57.                 selector = Selector.open();  
  58.                 ssc.register(selector, SelectionKey.OP_ACCEPT);  
  59.                   
  60.                 Set<SelectionKey> ops = null;  
  61.                 while(true) {  
  62.                     try {  
  63.                         selector.select(); //如果没有感兴趣的事件到达,阻塞等待  
  64.                         ops = selector.selectedKeys();  
  65.                     } catch(Throwable e) {  
  66.                         e.printStackTrace();  
  67.                         break;  
  68.                     }  
  69.                       
  70.                     //处理相关事件  
  71.                     for (Iterator<SelectionKey> it = ops.iterator(); it.hasNext();) {  
  72.                         SelectionKey key =  it.next();  
  73.                         it.remove();  
  74.                           
  75.                         try {  
  76.                             if(key.isAcceptable()) { //客户端建立连接  
  77.                                 ServerSocketChannel serverSc = (ServerSocketChannel) key.channel();//这里其实,可以直接使用ssl这个变量  
  78.                                 SocketChannel clientChannel = serverSc.accept();  
  79.                                 clientChannel.configureBlocking(false);  
  80.                                   
  81.                                 //向选择器注册读事件,客户端向服务端发送数据准备好后,再处理  
  82.                                 clientChannel.register(selector, SelectionKey.OP_READ);  
  83.                                   
  84.                                 System.out.println("收到客户端的连接请求。。。");  
  85.                             } else if (key.isWritable()) { //向客户端发送请求  
  86.                                 SocketChannel clientChannel = (SocketChannel)key.channel();  
  87.                                 ByteBuffer buf = (ByteBuffer)key.attachment();  
  88.                                 buf.flip();  
  89.                                 clientChannel.write(buf);  
  90.                                 System.out.println("服务端向客户端发送数据。。。");  
  91.                                 //重新注册读事件  
  92.                                 clientChannel.register(selector, SelectionKey.OP_READ);  
  93.                             } else if(key.isReadable()) {  //处理客户端发送的数据  
  94.                                 System.out.println("服务端接收客户端连接请求。。。");  
  95. //                              System.out.println(key);  
  96.                                 SocketChannel clientChannel = (SocketChannel)key.channel();  
  97. //                              System.out.println("clientChannel.isConnected():" + clientChannel.isConnected());  
  98. //                              System.out.println("clientChannel.isConnectionPending():" +clientChannel.isConnectionPending());  
  99. //                              System.out.println("clientChannel.isOpen():" + clientChannel.isOpen());  
  100. //                              System.out.println("clientChannel.finishConnect():" + clientChannel.finishConnect());  
  101.                                 ByteBuffer buf = ByteBuffer.allocate(1024);  
  102.                                 System.out.println(buf.capacity());  
  103.                                 clientChannel.read(buf);//  
  104.                                 buf.put(b);  
  105.                                 clientChannel.register(selector, SelectionKey.OP_WRITE, buf);//注册写事件  
  106.                             }  
  107.                         } catch(Throwable e) {  
  108.                             e.printStackTrace();  
  109.                             System.out.println("客户端主动断开连接。。。。。。。");  
  110.                             ssc.register(selector, SelectionKey.OP_ACCEPT);  
  111.                         }  
  112.                           
  113.                     }  
  114.                 }  
  115.                   
  116.             } catch (IOException e) {  
  117.                 // TODO Auto-generated catch block  
  118.                 e.printStackTrace();  
  119.             }  
  120.               
  121.         }  
  122.           
  123.     }  
  124.   
  125. }  
package threadmode.r1;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

/**
 * Nio服务器,
 * 本例主要用来增加对 Ractor 线程模型的理解,不会考虑半包等网络问题
 * 
 * 例子程序的功能:服务器接受客户端的请求数据,然后在后面再追加 (hello,服务器收到了你的信息。)
 * @author dingwei2
 * 
 * 
 * 
 * 
 *
 */
public class NioServer {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		// 
		(new Thread(new Reactor())).start();

	}
	
	/**
	 * Reactor模型,反应堆
	 * @author dingwei2
	 *
	 */
	private static final class Reactor implements Runnable {
		
//		private static final ConcurrentHashMap<SocketChannel, ByteBuffer> waitSendData 
//											= new ConcurrentHashMap<SocketChannel, ByteBuffer>();
		
		private static final byte[] b = "hello,服务器收到了你的信息。".getBytes();

		public void run() {
			// TODO Auto-generated method stub
			System.out.println("服务端启动成功,等待客户端接入");
			ServerSocketChannel ssc = null;
			Selector selector = null;
			try {
				ssc = ServerSocketChannel.open();
				ssc.configureBlocking(false);
				ssc.bind(new InetSocketAddress("127.0.0.1", 9080));
				
				selector = Selector.open();
				ssc.register(selector, SelectionKey.OP_ACCEPT);
				
				Set<SelectionKey> ops = null;
				while(true) {
					try {
						selector.select(); //如果没有感兴趣的事件到达,阻塞等待
						ops = selector.selectedKeys();
					} catch(Throwable e) {
						e.printStackTrace();
						break;
					}
					
					//处理相关事件
					for (Iterator<SelectionKey> it = ops.iterator(); it.hasNext();) {
						SelectionKey key =  it.next();
						it.remove();
						
						try {
							if(key.isAcceptable()) { //客户端建立连接
								ServerSocketChannel serverSc = (ServerSocketChannel) key.channel();//这里其实,可以直接使用ssl这个变量
								SocketChannel clientChannel = serverSc.accept();
								clientChannel.configureBlocking(false);
								
								//向选择器注册读事件,客户端向服务端发送数据准备好后,再处理
								clientChannel.register(selector, SelectionKey.OP_READ);
								
								System.out.println("收到客户端的连接请求。。。");
							} else if (key.isWritable()) { //向客户端发送请求
								SocketChannel clientChannel = (SocketChannel)key.channel();
								ByteBuffer buf = (ByteBuffer)key.attachment();
								buf.flip();
								clientChannel.write(buf);
								System.out.println("服务端向客户端发送数据。。。");
								//重新注册读事件
								clientChannel.register(selector, SelectionKey.OP_READ);
							} else if(key.isReadable()) {  //处理客户端发送的数据
								System.out.println("服务端接收客户端连接请求。。。");
//								System.out.println(key);
								SocketChannel clientChannel = (SocketChannel)key.channel();
//								System.out.println("clientChannel.isConnected():" + clientChannel.isConnected());
//								System.out.println("clientChannel.isConnectionPending():" +clientChannel.isConnectionPending());
//								System.out.println("clientChannel.isOpen():" + clientChannel.isOpen());
//								System.out.println("clientChannel.finishConnect():" + clientChannel.finishConnect());
								ByteBuffer buf = ByteBuffer.allocate(1024);
								System.out.println(buf.capacity());
								clientChannel.read(buf);//
								buf.put(b);
								clientChannel.register(selector, SelectionKey.OP_WRITE, buf);//注册写事件
							}
						} catch(Throwable e) {
							e.printStackTrace();
							System.out.println("客户端主动断开连接。。。。。。。");
							ssc.register(selector, SelectionKey.OP_ACCEPT);
						}
						
					}
				}
				
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}
		
	}

}

Nio客户端代码

 

 

[java] view plain copy
 
print?
  1. package threadmode.r1;  
  2.   
  3. import java.io.IOException;  
  4. import java.net.InetSocketAddress;  
  5. import java.nio.ByteBuffer;  
  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. /** 
  12.  * @author dingwei2 
  13.  * 
  14.  */  
  15. public class NioClient {  
  16.   
  17.     public static void main(String[] args) {  
  18.         // TODO Auto-generated method stub  
  19.           
  20.         SocketChannel clientClient;  
  21.         Selector selector = null;  
  22.         try {  
  23.             clientClient = SocketChannel.open();  
  24.             clientClient.configureBlocking(false);  
  25.               
  26.             selector = Selector.open();  
  27.               
  28.             clientClient.register(selector, SelectionKey.OP_CONNECT);  
  29.               
  30.             clientClient.connect(new InetSocketAddress("127.0.0.1",9080));  
  31.               
  32.             Set<SelectionKey> ops = null;  
  33.               
  34.             while(true) {  
  35.                 try {  
  36.                     selector.select();  
  37.                     ops = selector.selectedKeys();  
  38.                     for (Iterator<SelectionKey> it = ops.iterator(); it.hasNext();) {  
  39.                         SelectionKey key = it.next();  
  40.                         it.remove();  
  41.                         if(key.isConnectable()) {  
  42.                             System.out.println("client connect");  
  43.                             SocketChannel sc =  (SocketChannel) key.channel();  
  44.                             // 判断此通道上是否正在进行连接操作。  
  45.                             // 完成套接字通道的连接过程。  
  46.                             if (sc.isConnectionPending()) {  
  47.                                 sc.finishConnect();  
  48.                                 System.out.println("完成连接!");  
  49.                                 ByteBuffer buffer = ByteBuffer.allocate(1024);  
  50.                                 buffer.put("Hello,Server".getBytes());  
  51.                                 buffer.flip();  
  52.                                 sc.write(buffer);  
  53.                             }  
  54.                             sc.register(selector, SelectionKey.OP_READ);   
  55.                         } else if(key.isWritable()) {  
  56.                             System.out.println("客户端写");  
  57.                             SocketChannel sc = (SocketChannel)key.channel();  
  58.                             ByteBuffer buffer = ByteBuffer.allocate(1024);  
  59.                             buffer.put("hello server.".getBytes());  
  60.                             buffer.flip();  
  61.                             sc.write(buffer);  
  62.                         } else if(key.isReadable()) {  
  63.                             System.out.println("客户端收到服务器的响应....");  
  64.                             SocketChannel sc = (SocketChannel)key.channel();  
  65.                             ByteBuffer buffer = ByteBuffer.allocate(1024);  
  66.                             int count = sc.read(buffer);  
  67.                             if(count > 0 ) {  
  68.                                 buffer.flip();  
  69.                                 byte[] response = new byte[buffer.remaining()];  
  70.                                 buffer.get(response);  
  71.                                 System.out.println(new String(response));  
  72.                             }  
  73.                               
  74.                         }  
  75.                           
  76.                     }  
  77.                       
  78.                 } catch(Throwable e) {  
  79.                     e.printStackTrace();  
  80.                 }  
  81.                   
  82.             }  
  83.               
  84.               
  85.               
  86.               
  87.               
  88.               
  89.         } catch (IOException e) {  
  90.             // TODO Auto-generated catch block  
  91.             e.printStackTrace();  
  92.         }  
  93.           
  94.   
  95.     }  
  96.   
  97. }  
package threadmode.r1;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
/**
 * @author dingwei2
 *
 */
public class NioClient {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		SocketChannel clientClient;
		Selector selector = null;
		try {
			clientClient = SocketChannel.open();
			clientClient.configureBlocking(false);
			
			selector = Selector.open();
			
			clientClient.register(selector, SelectionKey.OP_CONNECT);
			
			clientClient.connect(new InetSocketAddress("127.0.0.1",9080));
			
			Set<SelectionKey> ops = null;
			
			while(true) {
				try {
					selector.select();
					ops = selector.selectedKeys();
					for (Iterator<SelectionKey> it = ops.iterator(); it.hasNext();) {
						SelectionKey key = it.next();
						it.remove();
						if(key.isConnectable()) {
							System.out.println("client connect");
							SocketChannel sc =  (SocketChannel) key.channel();
							// 判断此通道上是否正在进行连接操作。
							// 完成套接字通道的连接过程。
							if (sc.isConnectionPending()) {
								sc.finishConnect();
								System.out.println("完成连接!");
								ByteBuffer buffer = ByteBuffer.allocate(1024);
								buffer.put("Hello,Server".getBytes());
								buffer.flip();
								sc.write(buffer);
							}
							sc.register(selector, SelectionKey.OP_READ); 
						} else if(key.isWritable()) {
							System.out.println("客户端写");
							SocketChannel sc = (SocketChannel)key.channel();
							ByteBuffer buffer = ByteBuffer.allocate(1024);
							buffer.put("hello server.".getBytes());
							buffer.flip();
							sc.write(buffer);
						} else if(key.isReadable()) {
							System.out.println("客户端收到服务器的响应....");
							SocketChannel sc = (SocketChannel)key.channel();
							ByteBuffer buffer = ByteBuffer.allocate(1024);
							int count = sc.read(buffer);
							if(count > 0 ) {
								buffer.flip();
								byte[] response = new byte[buffer.remaining()];
								buffer.get(response);
								System.out.println(new String(response));
							}
							
						}
						
					}
					
				} catch(Throwable e) {
					e.printStackTrace();
				}
				
			}
			
			
			
			
			
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		

	}

}

 

 

1.2 多线程模型


Reactor多线程模型(多个Nio线程处理网络读写)(此图来源与网络)

1.2多线程模型,就是1个线程Acceptor接受客户端的连接,然后由一组IO线程(Reactor)来执行网络的读写。

下面贴出其实现

其中NioServer中的Acceptor为接受客户端连接线程。

其中NioReactorThreadGroup为一组IO线程,NioReactorThread为具体IO线程的实现。

 

[java] view plain copy
 
print?
  1. package threadmode.r2;  
  2.   
  3. import java.io.IOException;  
  4. import java.net.InetSocketAddress;  
  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.   
  12. public class NioServer {  
  13.   
  14.     public static void main(String[] args) {  
  15.         // TODO Auto-generated method stub  
  16.           
  17.         new Thread(new Acceptor()).start();  
  18.   
  19.     }  
  20.   
  21.     /** 
  22.      * 连接线程模型,反应堆,转发器 Acceptor 
  23.      *  
  24.      * @author dingwei2 
  25.      * 
  26.      */  
  27.     private static final class Acceptor implements Runnable {  
  28.   
  29.         private NioReactorThreadGroup nioReactorThreadGroup;  
  30.           
  31.         public Acceptor() {  
  32.             nioReactorThreadGroup = new NioReactorThreadGroup();  
  33.         }  
  34.   
  35.         public void run() {  
  36.             // TODO Auto-generated method stub  
  37.             System.out.println("服务端启动成功,等待客户端接入");  
  38.             ServerSocketChannel ssc = null;  
  39.             Selector selector = null;  
  40.             try {  
  41.                 ssc = ServerSocketChannel.open();  
  42.                 ssc.configureBlocking(false);  
  43.                 ssc.bind(new InetSocketAddress("127.0.0.1"9080));  
  44.   
  45.                 selector = Selector.open();  
  46.                 ssc.register(selector, SelectionKey.OP_ACCEPT);  
  47.   
  48.                 Set<SelectionKey> ops = null;  
  49.                 while (true) {  
  50.                     try {  
  51.                         selector.select(); // 如果没有感兴趣的事件到达,阻塞等待  
  52.                         ops = selector.selectedKeys();  
  53.                     } catch (Throwable e) {  
  54.                         e.printStackTrace();  
  55.                         break;  
  56.                     }  
  57.   
  58.                     // 处理相关事件  
  59.                     for (Iterator<SelectionKey> it = ops.iterator(); it.hasNext();) {  
  60.                         SelectionKey key = it.next();  
  61.                         it.remove();  
  62.   
  63.                         try {  
  64.                             if (key.isAcceptable()) { // 客户端建立连接  
  65.                                 System.out.println("收到客户端的连接请求。。。");  
  66.                                 ServerSocketChannel serverSc = (ServerSocketChannel) key.channel();// 这里其实,可以直接使用ssl这个变量  
  67.                                 SocketChannel clientChannel = serverSc.accept();  
  68.                                 clientChannel.configureBlocking(false);  
  69.                                 nioReactorThreadGroup.dispatch(clientChannel); // 转发该请求  
  70.                             }  
  71.                         } catch (Throwable e) {  
  72.                             e.printStackTrace();  
  73.                             System.out.println("客户端主动断开连接。。。。。。。");  
  74.                         }  
  75.   
  76.                     }  
  77.                 }  
  78.   
  79.             } catch (IOException e) {  
  80.                 // TODO Auto-generated catch block  
  81.                 e.printStackTrace();  
  82.             }  
  83.   
  84.         }  
  85.   
  86.     }  
  87.   
  88. }  
package threadmode.r2;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

public class NioServer {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		new Thread(new Acceptor()).start();

	}

	/**
	 * 连接线程模型,反应堆,转发器 Acceptor
	 * 
	 * @author dingwei2
	 *
	 */
	private static final class Acceptor implements Runnable {

		private NioReactorThreadGroup nioReactorThreadGroup;
		
		public Acceptor() {
			nioReactorThreadGroup = new NioReactorThreadGroup();
		}

		public void run() {
			// TODO Auto-generated method stub
			System.out.println("服务端启动成功,等待客户端接入");
			ServerSocketChannel ssc = null;
			Selector selector = null;
			try {
				ssc = ServerSocketChannel.open();
				ssc.configureBlocking(false);
				ssc.bind(new InetSocketAddress("127.0.0.1", 9080));

				selector = Selector.open();
				ssc.register(selector, SelectionKey.OP_ACCEPT);

				Set<SelectionKey> ops = null;
				while (true) {
					try {
						selector.select(); // 如果没有感兴趣的事件到达,阻塞等待
						ops = selector.selectedKeys();
					} catch (Throwable e) {
						e.printStackTrace();
						break;
					}

					// 处理相关事件
					for (Iterator<SelectionKey> it = ops.iterator(); it.hasNext();) {
						SelectionKey key = it.next();
						it.remove();

						try {
							if (key.isAcceptable()) { // 客户端建立连接
								System.out.println("收到客户端的连接请求。。。");
								ServerSocketChannel serverSc = (ServerSocketChannel) key.channel();// 这里其实,可以直接使用ssl这个变量
								SocketChannel clientChannel = serverSc.accept();
								clientChannel.configureBlocking(false);
								nioReactorThreadGroup.dispatch(clientChannel); // 转发该请求
							}
						} catch (Throwable e) {
							e.printStackTrace();
							System.out.println("客户端主动断开连接。。。。。。。");
						}

					}
				}

			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		}

	}

}
[java] view plain copy
 
print?
  1. package threadmode.r2;  
  2.   
  3. import java.nio.channels.SocketChannel;  
  4. import java.util.concurrent.atomic.AtomicInteger;  
  5.   
  6. /** 
  7.  * nio 线程组;简易的NIO线程组 
  8.  * @author dingwei2 
  9.  * 
  10.  */  
  11. public class NioReactorThreadGroup {  
  12.       
  13.     private static final AtomicInteger requestCounter = new AtomicInteger();  //请求计数器  
  14.       
  15.     private final int nioThreadCount;  // 线程池IO线程的数量  
  16.     private static final int DEFAULT_NIO_THREAD_COUNT;   
  17.     private NioReactorThread[] nioThreads;  
  18.       
  19.     static {  
  20. //      DEFAULT_NIO_THREAD_COUNT = Runtime.getRuntime().availableProcessors() > 1  
  21. //              ? 2 * (Runtime.getRuntime().availableProcessors() - 1 ) : 2;  
  22.           
  23.         DEFAULT_NIO_THREAD_COUNT = 4;  
  24.     }  
  25.       
  26.     public NioReactorThreadGroup() {  
  27.         this(DEFAULT_NIO_THREAD_COUNT);  
  28.     }  
  29.       
  30.     public NioReactorThreadGroup(int threadCount) {  
  31.         if(threadCount < 1) {  
  32.             threadCount = DEFAULT_NIO_THREAD_COUNT;  
  33.         }  
  34.         this.nioThreadCount = threadCount;  
  35.         this.nioThreads = new NioReactorThread[threadCount];  
  36.         for(int i = 0; i < threadCount; i ++ ) {  
  37.             this.nioThreads[i] = new NioReactorThread();  
  38.             this.nioThreads[i].start(); //构造方法中启动线程,由于nioThreads不会对外暴露,故不会引起线程逃逸  
  39.         }  
  40.           
  41.         System.out.println("Nio 线程数量:" + threadCount);  
  42.     }  
  43.       
  44.     public void dispatch(SocketChannel socketChannel) {  
  45.         if(socketChannel != null ) {  
  46.             next().register(socketChannel);  
  47.         }  
  48.     }  
  49.       
  50.     protected NioReactorThread next() {  
  51.         return this.nioThreads[ requestCounter.getAndIncrement() %  nioThreadCount ];  
  52.     }  
  53.       
  54.       
  55.   
  56.     public static void main(String[] args) {  
  57.         // TODO Auto-generated method stub  
  58.   
  59.     }  
  60.   
  61. }  
package threadmode.r2;

import java.nio.channels.SocketChannel;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * nio 线程组;简易的NIO线程组
 * @author dingwei2
 *
 */
public class NioReactorThreadGroup {
	
	private static final AtomicInteger requestCounter = new AtomicInteger();  //请求计数器
	
	private final int nioThreadCount;  // 线程池IO线程的数量
	private static final int DEFAULT_NIO_THREAD_COUNT; 
	private NioReactorThread[] nioThreads;
	
	static {
//		DEFAULT_NIO_THREAD_COUNT = Runtime.getRuntime().availableProcessors() > 1
//				? 2 * (Runtime.getRuntime().availableProcessors() - 1 ) : 2;
		
		DEFAULT_NIO_THREAD_COUNT = 4;
	}
	
	public NioReactorThreadGroup() {
		this(DEFAULT_NIO_THREAD_COUNT);
	}
	
	public NioReactorThreadGroup(int threadCount) {
		if(threadCount < 1) {
			threadCount = DEFAULT_NIO_THREAD_COUNT;
		}
		this.nioThreadCount = threadCount;
		this.nioThreads = new NioReactorThread[threadCount];
		for(int i = 0; i < threadCount; i ++ ) {
			this.nioThreads[i] = new NioReactorThread();
			this.nioThreads[i].start(); //构造方法中启动线程,由于nioThreads不会对外暴露,故不会引起线程逃逸
		}
		
		System.out.println("Nio 线程数量:" + threadCount);
	}
	
	public void dispatch(SocketChannel socketChannel) {
		if(socketChannel != null ) {
			next().register(socketChannel);
		}
	}
	
	protected NioReactorThread next() {
		return this.nioThreads[ requestCounter.getAndIncrement() %  nioThreadCount ];
	}
	
	

	public static void main(String[] args) {
		// TODO Auto-generated method stub

	}

}
[java] view plain copy
 
print?
  1. package threadmode.r2;  
  2.   
  3. import java.io.IOException;  
  4. import java.nio.ByteBuffer;  
  5. import java.nio.channels.SelectionKey;  
  6. import java.nio.channels.Selector;  
  7. import java.nio.channels.SocketChannel;  
  8. import java.util.ArrayList;  
  9. import java.util.Iterator;  
  10. import java.util.List;  
  11. import java.util.Set;  
  12. import java.util.concurrent.locks.ReentrantLock;  
  13.   
  14. /** 
  15.  * Nio 线程,专门负责nio read,write 
  16.  * 本类是实例行代码,不会对nio,断线重连,写半包等场景进行处理,旨在理解 Reactor模型(多线程版本) 
  17.  * @author dingwei2 
  18.  * 
  19.  */  
  20. public class NioReactorThread extends Thread {  
  21.       
  22.     private static final byte[] b = "hello,服务器收到了你的信息。".getBytes(); //服务端给客户端的响应  
  23.       
  24.     private Selector selector;  
  25.     private List<SocketChannel> waitRegisterList = new ArrayList<SocketChannel>(512);  
  26.     private ReentrantLock registerLock = new ReentrantLock();  
  27.       
  28.       
  29.     public NioReactorThread() {  
  30.         try {  
  31.             this.selector = Selector.open();  
  32.         } catch (IOException e) {  
  33.             // TODO Auto-generated catch block  
  34.             e.printStackTrace();  
  35.         }  
  36.     }  
  37.       
  38.     /** 
  39.      * socket channel 
  40.      * @param socketChannel 
  41.      */  
  42.     public void register(SocketChannel socketChannel) {  
  43.         if(socketChannel != null ) {  
  44.             try {  
  45.                 registerLock.lock();  
  46.                 waitRegisterList.add(socketChannel);  
  47.             } finally {  
  48.                 registerLock.unlock();  
  49.             }  
  50.         }  
  51.     }  
  52.       
  53.     //private   
  54.   
  55.     public void run() {  
  56.         while(true) {  
  57.             Set<SelectionKey> ops = null;  
  58.             try {  
  59.                 selector.select(1000);  
  60.                 ops = selector.selectedKeys();  
  61.             } catch (IOException e) {  
  62.                 // TODO Auto-generated catch block  
  63.                 e.printStackTrace();  
  64.                 continue;  
  65.             }  
  66.               
  67.             //处理相关事件  
  68.             for (Iterator<SelectionKey> it = ops.iterator(); it.hasNext();) {  
  69.                 SelectionKey key =  it.next();  
  70.                 it.remove();  
  71.                   
  72.                 try {  
  73.                     if (key.isWritable()) { //向客户端发送请求  
  74.                         SocketChannel clientChannel = (SocketChannel)key.channel();  
  75.                         ByteBuffer buf = (ByteBuffer)key.attachment();  
  76.                         buf.flip();  
  77.                         clientChannel.write(buf);  
  78.                         System.out.println("服务端向客户端发送数据。。。");  
  79.                         //重新注册读事件  
  80.                         clientChannel.register(selector, SelectionKey.OP_READ);  
  81.                     } else if(key.isReadable()) {  //接受客户端请求  
  82.                         System.out.println("服务端接收客户端连接请求。。。");  
  83.                         SocketChannel clientChannel = (SocketChannel)key.channel();  
  84.                         ByteBuffer buf = ByteBuffer.allocate(1024);  
  85.                         System.out.println(buf.capacity());  
  86.                         clientChannel.read(buf);//  
  87.                         buf.put(b);  
  88.                         clientChannel.register(selector, SelectionKey.OP_WRITE, buf);//注册写事件  
  89.                     }  
  90.                 } catch(Throwable e) {  
  91.                     e.printStackTrace();  
  92.                     System.out.println("客户端主动断开连接。。。。。。。");  
  93.                 }  
  94.                   
  95.             }  
  96.               
  97.             //注册事件  
  98.             if(!waitRegisterList.isEmpty()) {  
  99.                 try {  
  100.                     registerLock.lock();  
  101.                     for (Iterator<SocketChannel> it = waitRegisterList.iterator(); it.hasNext();) {  
  102.                         SocketChannel sc = it.next();  
  103.                         try {  
  104.                             sc.register(selector, SelectionKey.OP_READ);  
  105.                         } catch(Throwable e) {  
  106.                             e.printStackTrace();//ignore  
  107.                         }  
  108.                         it.remove();  
  109.                     }  
  110.                       
  111.                 } finally {  
  112.                     registerLock.unlock();  
  113.                 }  
  114.             }  
  115.               
  116.               
  117.         }  
  118.     }  
  119.   
  120. }  
package threadmode.r2;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Nio 线程,专门负责nio read,write
 * 本类是实例行代码,不会对nio,断线重连,写半包等场景进行处理,旨在理解 Reactor模型(多线程版本)
 * @author dingwei2
 *
 */
public class NioReactorThread extends Thread {
	
	private static final byte[] b = "hello,服务器收到了你的信息。".getBytes(); //服务端给客户端的响应
	
	private Selector selector;
	private List<SocketChannel> waitRegisterList = new ArrayList<SocketChannel>(512);
	private ReentrantLock registerLock = new ReentrantLock();
	
	
	public NioReactorThread() {
		try {
			this.selector = Selector.open();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	/**
	 * socket channel
	 * @param socketChannel
	 */
	public void register(SocketChannel socketChannel) {
		if(socketChannel != null ) {
			try {
				registerLock.lock();
				waitRegisterList.add(socketChannel);
			} finally {
				registerLock.unlock();
			}
		}
	}
	
	//private 

	public void run() {
		while(true) {
			Set<SelectionKey> ops = null;
			try {
				selector.select(1000);
				ops = selector.selectedKeys();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				continue;
			}
			
			//处理相关事件
			for (Iterator<SelectionKey> it = ops.iterator(); it.hasNext();) {
				SelectionKey key =  it.next();
				it.remove();
				
				try {
					if (key.isWritable()) { //向客户端发送请求
						SocketChannel clientChannel = (SocketChannel)key.channel();
						ByteBuffer buf = (ByteBuffer)key.attachment();
						buf.flip();
						clientChannel.write(buf);
						System.out.println("服务端向客户端发送数据。。。");
						//重新注册读事件
						clientChannel.register(selector, SelectionKey.OP_READ);
					} else if(key.isReadable()) {  //接受客户端请求
						System.out.println("服务端接收客户端连接请求。。。");
						SocketChannel clientChannel = (SocketChannel)key.channel();
						ByteBuffer buf = ByteBuffer.allocate(1024);
						System.out.println(buf.capacity());
						clientChannel.read(buf);//
						buf.put(b);
						clientChannel.register(selector, SelectionKey.OP_WRITE, buf);//注册写事件
					}
				} catch(Throwable e) {
					e.printStackTrace();
					System.out.println("客户端主动断开连接。。。。。。。");
				}
				
			}
			
			//注册事件
			if(!waitRegisterList.isEmpty()) {
				try {
					registerLock.lock();
					for (Iterator<SocketChannel> it = waitRegisterList.iterator(); it.hasNext();) {
						SocketChannel sc = it.next();
						try {
							sc.register(selector, SelectionKey.OP_READ);
						} catch(Throwable e) {
							e.printStackTrace();//ignore
						}
						it.remove();
					}
					
				} finally {
					registerLock.unlock();
				}
			}
			
			
		}
	}

}
NioClient与Reactor,单线程版本一样,在这不重复给出。

 

 

上述示例代码中,其实并不是完成按照Reacor设计模式而来的,重头戏请看1.3,主从多线程模型(Reacor)实现
1.3 主从多线程模型(Reactor)

 


主从多线程模型(此图来源与网络)
 

重点关注点如下:

Acceeptor,职责,维护Java.nio.ServerSocketChannel类,绑定服务端监听端口,然后将该通道注册到MainRector中;

Main Reactor,监听客户端连接的反应堆,这里使用jdk并发中的Executors.newSingleThreadExecutor线程池来实现,监听客户端的连接事件(OP_ACCEPT)

Sub Reactor,目前没有使用jdk的并发池,这里用的SubReactorThreadGroup,其实现是数组,当然这里也可以使用jdk线程池,SubReactor的每一个线程都是IO线程,用来处理读,写事件。所有的IO线程公用一个业务线程池(基于juc)实现,用来处理业务逻辑,也就是运行Handel的地方。

Handel:具体业务逻辑实现,本例就是获取客户端的信息后,在请求信息后面追加一段文字,便返回给客户端。相关源码实现:

NioServer(Acceptor)的实现源码:

 

[java] view plain copy
 
print?
  1. package persistent.prestige.demo.netty.threadmode.t3;  
  2.   
  3. import java.io.IOException;  
  4. import java.net.InetSocketAddress;  
  5. import java.nio.channels.ServerSocketChannel;  
  6. import java.util.concurrent.ExecutorService;  
  7. import java.util.concurrent.Executors;  
  8.   
  9.   
  10. /** 
  11.  * Reactor 主从Reactor模式实现 
  12.  *  
  13.  * Acceptor,其实个人认为,这里就是服务端角色 
  14.  * @author Administrator 
  15.  * 
  16.  */  
  17. public class NioServer {  
  18.       
  19.     private static final int DEFAULT_PORT = 9080;  
  20.       
  21.     public static void main(String[] args) {  
  22.           
  23.         new Thread(new Acceptor()).start();  
  24.           
  25.     }  
  26.       
  27.       
  28.     private static class Acceptor implements Runnable {  
  29.           
  30.         // main Reactor 线程池,用于处理客户端的连接请求  
  31.         private static ExecutorService mainReactor = Executors.newSingleThreadExecutor();  
  32.   
  33.         public void run() {  
  34.             // TODO Auto-generated method stub  
  35.             ServerSocketChannel ssc = null;  
  36.               
  37.             try {  
  38.                 ssc = ServerSocketChannel.open();  
  39.                 ssc.configureBlocking(false);  
  40.                 ssc.bind(new InetSocketAddress(DEFAULT_PORT));  
  41.                   
  42.                 //转发到 MainReactor反应堆  
  43.                 dispatch(ssc);  
  44.                   
  45.                 System.out.println("服务端成功启动。。。。。。");  
  46.                   
  47.             } catch (IOException e) {  
  48.                 // TODO Auto-generated catch block  
  49.                 e.printStackTrace();  
  50.             }  
  51.         }  
  52.           
  53.         private void dispatch(ServerSocketChannel ssc) {  
  54.             mainReactor.submit(new MainReactor(ssc));  
  55.         }  
  56.           
  57.     }  
  58.       
  59.   
  60. }  
package persistent.prestige.demo.netty.threadmode.t3;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.ServerSocketChannel;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


/**
 * Reactor 主从Reactor模式实现
 * 
 * Acceptor,其实个人认为,这里就是服务端角色
 * @author Administrator
 *
 */
public class NioServer {
	
	private static final int DEFAULT_PORT = 9080;
	
	public static void main(String[] args) {
		
		new Thread(new Acceptor()).start();
		
	}
	
	
	private static class Acceptor implements Runnable {
		
		// main Reactor 线程池,用于处理客户端的连接请求
		private static ExecutorService mainReactor = Executors.newSingleThreadExecutor();

		public void run() {
			// TODO Auto-generated method stub
			ServerSocketChannel ssc = null;
			
			try {
				ssc = ServerSocketChannel.open();
				ssc.configureBlocking(false);
				ssc.bind(new InetSocketAddress(DEFAULT_PORT));
				
				//转发到 MainReactor反应堆
				dispatch(ssc);
				
				System.out.println("服务端成功启动。。。。。。");
				
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
		private void dispatch(ServerSocketChannel ssc) {
			mainReactor.submit(new MainReactor(ssc));
		}
		
	}
	

}
MainReactor 源码如下:

 

 

[java] view plain copy
 
print?
  1. package persistent.prestige.demo.netty.threadmode.t3;  
  2.   
  3. import java.io.IOException;  
  4. import java.nio.channels.SelectableChannel;  
  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.   
  12.   
  13. /** 
  14.  * 主Reactor,主要用来处理连接请求的反应堆 
  15.  * @author Administrator 
  16.  * 
  17.  */  
  18. public class MainReactor implements Runnable {  
  19.       
  20.     private Selector selector;  
  21.     private SubReactorThreadGroup subReactorThreadGroup;   
  22.       
  23.     public MainReactor(SelectableChannel channel) {  
  24.         try {  
  25.             selector = Selector.open();  
  26.             channel.register(selector, SelectionKey.OP_ACCEPT);  
  27.         } catch (IOException e) {  
  28.             // TODO Auto-generated catch block  
  29.             e.printStackTrace();  
  30.         }  
  31.           
  32.         subReactorThreadGroup = new SubReactorThreadGroup(4);  
  33.     }  
  34.   
  35.     public void run() {  
  36.           
  37.         System.out.println("MainReactor is running");  
  38.         // TODO Auto-generated method stub  
  39.         while (!Thread.interrupted()) {  
  40.               
  41.             Set<SelectionKey> ops = null;  
  42.             try {  
  43.                 selector.select(1000);  
  44.                 ops = selector.selectedKeys();  
  45.             } catch (IOException e) {  
  46.                 // TODO Auto-generated catch block  
  47.                 e.printStackTrace();  
  48.             }  
  49.               
  50.             // 处理相关事件    
  51.             for (Iterator<SelectionKey> it = ops.iterator(); it.hasNext();) {    
  52.                 SelectionKey key = it.next();    
  53.                 it.remove();    
  54.                 try {    
  55.                     if (key.isAcceptable()) { // 客户端建立连接    
  56.                         System.out.println("收到客户端的连接请求。。。");    
  57.                         ServerSocketChannel serverSc = (ServerSocketChannel) key.channel();// 这里其实,可以直接使用ssl这个变量    
  58.                         SocketChannel clientChannel = serverSc.accept();    
  59.                         clientChannel.configureBlocking(false);    
  60.                         subReactorThreadGroup.dispatch(clientChannel); // 转发该请求    
  61.                     }    
  62.                 } catch (Throwable e) {    
  63.                     e.printStackTrace();    
  64.                     System.out.println("客户端主动断开连接。。。。。。。");    
  65.                 }    
  66.   
  67.             }    
  68.                 
  69.               
  70.         }  
  71.   
  72.     }  
  73.   
  74. }  
package persistent.prestige.demo.netty.threadmode.t3;

import java.io.IOException;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;


/**
 * 主Reactor,主要用来处理连接请求的反应堆
 * @author Administrator
 *
 */
public class MainReactor implements Runnable {
	
	private Selector selector;
	private SubReactorThreadGroup subReactorThreadGroup; 
	
	public MainReactor(SelectableChannel channel) {
		try {
			selector = Selector.open();
			channel.register(selector, SelectionKey.OP_ACCEPT);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		subReactorThreadGroup = new SubReactorThreadGroup(4);
	}

	public void run() {
		
		System.out.println("MainReactor is running");
		// TODO Auto-generated method stub
		while (!Thread.interrupted()) {
			
			Set<SelectionKey> ops = null;
			try {
				selector.select(1000);
				ops = selector.selectedKeys();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			// 处理相关事件  
            for (Iterator<SelectionKey> it = ops.iterator(); it.hasNext();) {  
                SelectionKey key = it.next();  
                it.remove();  
                try {  
                    if (key.isAcceptable()) { // 客户端建立连接  
                        System.out.println("收到客户端的连接请求。。。");  
                        ServerSocketChannel serverSc = (ServerSocketChannel) key.channel();// 这里其实,可以直接使用ssl这个变量  
                        SocketChannel clientChannel = serverSc.accept();  
                        clientChannel.configureBlocking(false);  
                        subReactorThreadGroup.dispatch(clientChannel); // 转发该请求  
                    }  
                } catch (Throwable e) {  
                    e.printStackTrace();  
                    System.out.println("客户端主动断开连接。。。。。。。");  
                }  

            }  
			  
            
		}

	}

}

 

 

SubReactor组,IO线程池实现:

 

[java] view plain copy
 
print?
  1. package persistent.prestige.demo.netty.threadmode.t3;  
  2.   
  3. import java.nio.channels.SelectionKey;  
  4. import java.nio.channels.SocketChannel;    
  5. import java.util.concurrent.ExecutorService;  
  6. import java.util.concurrent.Executors;  
  7. import java.util.concurrent.atomic.AtomicInteger;    
  8.     
  9. /**  
  10.  * nio 线程组;简易的NIO线程组  
  11.  * @author dingwei2  
  12.  *  
  13.  */    
  14. public class SubReactorThreadGroup {    
  15.         
  16.     private static final AtomicInteger requestCounter = new AtomicInteger();  //请求计数器    
  17.         
  18.     private final int nioThreadCount;  // 线程池IO线程的数量    
  19.     private static final int DEFAULT_NIO_THREAD_COUNT;     
  20.     private SubReactorThread[] nioThreads;    
  21.     private ExecutorService businessExecutePool; //业务线程池  
  22.         
  23.     static {    
  24. //      DEFAULT_NIO_THREAD_COUNT = Runtime.getRuntime().availableProcessors() > 1    
  25. //              ? 2 * (Runtime.getRuntime().availableProcessors() - 1 ) : 2;    
  26.             
  27.         DEFAULT_NIO_THREAD_COUNT = 4;    
  28.     }    
  29.         
  30.     public SubReactorThreadGroup() {    
  31.         this(DEFAULT_NIO_THREAD_COUNT);    
  32.     }    
  33.         
  34.     public SubReactorThreadGroup(int threadCount) {    
  35.           
  36.         if(threadCount < 1) {    
  37.             threadCount = DEFAULT_NIO_THREAD_COUNT;    
  38.         }    
  39.           
  40.         businessExecutePool = Executors.newFixedThreadPool(threadCount);  
  41.           
  42.         this.nioThreadCount = threadCount;    
  43.         this.nioThreads = new SubReactorThread[threadCount];    
  44.         for(int i = 0; i < threadCount; i ++ ) {    
  45.             this.nioThreads[i] = new SubReactorThread(businessExecutePool);    
  46.             this.nioThreads[i].start(); //构造方法中启动线程,由于nioThreads不会对外暴露,故不会引起线程逃逸    
  47.         }    
  48.             
  49.         System.out.println("Nio 线程数量:" + threadCount);    
  50.     }    
  51.         
  52.     public void dispatch(SocketChannel socketChannel) {    
  53.         if(socketChannel != null ) {    
  54.             next().register(new NioTask(socketChannel, SelectionKey.OP_READ));    
  55.         }    
  56.     }    
  57.         
  58.     protected SubReactorThread next() {    
  59.         return this.nioThreads[ requestCounter.getAndIncrement() %  nioThreadCount ];    
  60.     }    
  61.         
  62.         
  63.     
  64.     public static void main(String[] args) {    
  65.         // TODO Auto-generated method stub    
  66.     
  67.     }    
  68.     
  69. }    
package persistent.prestige.demo.netty.threadmode.t3;

import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;  
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;  
  
/** 
 * nio 线程组;简易的NIO线程组 
 * @author dingwei2 
 * 
 */  
public class SubReactorThreadGroup {  
      
    private static final AtomicInteger requestCounter = new AtomicInteger();  //请求计数器  
      
    private final int nioThreadCount;  // 线程池IO线程的数量  
    private static final int DEFAULT_NIO_THREAD_COUNT;   
    private SubReactorThread[] nioThreads;  
    private ExecutorService businessExecutePool; //业务线程池
      
    static {  
//      DEFAULT_NIO_THREAD_COUNT = Runtime.getRuntime().availableProcessors() > 1  
//              ? 2 * (Runtime.getRuntime().availableProcessors() - 1 ) : 2;  
          
        DEFAULT_NIO_THREAD_COUNT = 4;  
    }  
      
    public SubReactorThreadGroup() {  
        this(DEFAULT_NIO_THREAD_COUNT);  
    }  
      
    public SubReactorThreadGroup(int threadCount) {  
    	
        if(threadCount < 1) {  
            threadCount = DEFAULT_NIO_THREAD_COUNT;  
        }  
        
        businessExecutePool = Executors.newFixedThreadPool(threadCount);
        
        this.nioThreadCount = threadCount;  
        this.nioThreads = new SubReactorThread[threadCount];  
        for(int i = 0; i < threadCount; i ++ ) {  
            this.nioThreads[i] = new SubReactorThread(businessExecutePool);  
            this.nioThreads[i].start(); //构造方法中启动线程,由于nioThreads不会对外暴露,故不会引起线程逃逸  
        }  
          
        System.out.println("Nio 线程数量:" + threadCount);  
    }  
      
    public void dispatch(SocketChannel socketChannel) {  
        if(socketChannel != null ) {  
            next().register(new NioTask(socketChannel, SelectionKey.OP_READ));  
        }  
    }  
      
    protected SubReactorThread next() {  
        return this.nioThreads[ requestCounter.getAndIncrement() %  nioThreadCount ];  
    }  
      
      
  
    public static void main(String[] args) {  
        // TODO Auto-generated method stub  
  
    }  
  
}  

SubReactor线程实现(IO线程)

 

 

[java] view plain copy
 
print?
  1. package persistent.prestige.demo.netty.threadmode.t3;  
  2.   
  3. import java.io.IOException;  
  4. import java.nio.ByteBuffer;  
  5. import java.nio.channels.SelectionKey;  
  6. import java.nio.channels.Selector;  
  7. import java.nio.channels.SocketChannel;  
  8. import java.util.ArrayList;  
  9. import java.util.Iterator;  
  10. import java.util.List;  
  11. import java.util.Set;  
  12. import java.util.concurrent.ExecutorService;  
  13. import java.util.concurrent.locks.ReentrantLock;  
  14.   
  15. /**  
  16.  * Nio 线程,专门负责nio read,write  
  17.  * 本类是实例行代码,不会对nio,断线重连,写半包等场景进行处理,旨在理解 Reactor模型(多线程版本)  
  18.  * @author dingwei2  
  19.  *  
  20.  */    
  21. public class SubReactorThread extends Thread {  
  22.   
  23.     private Selector selector;  
  24.     private ExecutorService businessExecutorPool;  
  25.     private List<NioTask> taskList = new ArrayList<NioTask>(512);  
  26.     private ReentrantLock taskMainLock = new ReentrantLock();  
  27.   
  28.     /** 
  29.      * 业务线程池 
  30.      * @param businessExecutorPool 
  31.      */  
  32.     public SubReactorThread(ExecutorService businessExecutorPool) {  
  33.         try {  
  34.             this.businessExecutorPool = businessExecutorPool;  
  35.             this.selector = Selector.open();  
  36.         } catch (IOException e) {  
  37.             // TODO Auto-generated catch block  
  38.             e.printStackTrace();  
  39.         }  
  40.     }  
  41.   
  42.     /** 
  43.      * socket channel 
  44.      *  
  45.      * @param socketChannel 
  46.      */  
  47.     public void register(NioTask task) {  
  48.         if (task != null) {  
  49.             try {  
  50.                 taskMainLock.lock();  
  51.                 taskList.add(task);  
  52.             } finally {  
  53.                 taskMainLock.unlock();  
  54.             }  
  55.         }  
  56.     }  
  57.   
  58.     // private  
  59.   
  60.     public void run() {  
  61.         while (!Thread.interrupted()) {  
  62.             Set<SelectionKey> ops = null;  
  63.             try {  
  64.                 selector.select(1000);  
  65.                 ops = selector.selectedKeys();  
  66.             } catch (IOException e) {  
  67.                 // TODO Auto-generated catch block  
  68.                 e.printStackTrace();  
  69.                 continue;  
  70.             }  
  71.   
  72.             // 处理相关事件  
  73.             for (Iterator<SelectionKey> it = ops.iterator(); it.hasNext();) {  
  74.                 SelectionKey key = it.next();  
  75.                 it.remove();  
  76.   
  77.                 try {  
  78.                     if (key.isWritable()) { // 向客户端发送请求  
  79.                         SocketChannel clientChannel = (SocketChannel) key  
  80.                                 .channel();  
  81.                         ByteBuffer buf = (ByteBuffer) key.attachment();  
  82.                         buf.flip();  
  83.                         clientChannel.write(buf);  
  84.                         System.out.println("服务端向客户端发送数据。。。");  
  85.                         // 重新注册读事件  
  86.                         clientChannel.register(selector, SelectionKey.OP_READ);  
  87.                     } else if (key.isReadable()) { // 接受客户端请求  
  88.                         System.out.println("服务端接收客户端连接请求。。。");  
  89.                         SocketChannel clientChannel = (SocketChannel) key  
  90.                                 .channel();  
  91.                         ByteBuffer buf = ByteBuffer.allocate(1024);  
  92.                         System.out.println(buf.capacity());  
  93.                         clientChannel.read(buf);//解析请求完毕  
  94.                           
  95.                         //转发请求到具体的业务线程;当然,这里其实可以向dubbo那样,支持转发策略,如果执行时间短,  
  96.                         //,比如没有数据库操作等,可以在io线程中执行。本实例,转发到业务线程池  
  97.                         dispatch(clientChannel, buf);  
  98.                           
  99.                     }  
  100.                 } catch (Throwable e) {  
  101.                     e.printStackTrace();  
  102.                     System.out.println("客户端主动断开连接。。。。。。。");  
  103.                 }  
  104.   
  105.             }  
  106.   
  107.             // 注册事件  
  108.             if (!taskList.isEmpty()) {  
  109.                 try {  
  110.                     taskMainLock.lock();  
  111.                     for (Iterator<NioTask> it = taskList  
  112.                             .iterator(); it.hasNext();) {  
  113.                         NioTask task = it.next();  
  114.                         try {  
  115.                             SocketChannel sc = task.getSc();  
  116.                             if(task.getData() != null) {  
  117.                                 sc.register(selector, task.getOp(), task.getData());  
  118.                             } else {  
  119.                                 sc.register(selector, task.getOp());  
  120.                             }  
  121.                               
  122.                         } catch (Throwable e) {  
  123.                             e.printStackTrace();// ignore  
  124.                         }  
  125.                         it.remove();  
  126.                     }  
  127.   
  128.                 } finally {  
  129.                     taskMainLock.unlock();  
  130.                 }  
  131.             }  
  132.   
  133.         }  
  134.     }  
  135.       
  136.     /** 
  137.      * 此处的reqBuffer处于可写状态 
  138.      * @param sc 
  139.      * @param reqBuffer 
  140.      */  
  141.     private void dispatch(SocketChannel sc, ByteBuffer reqBuffer) {  
  142.         businessExecutorPool.submit( new Handler(sc, reqBuffer, this)  );  
  143.     }  
  144. }  
package persistent.prestige.demo.netty.threadmode.t3;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.locks.ReentrantLock;

/** 
 * Nio 线程,专门负责nio read,write 
 * 本类是实例行代码,不会对nio,断线重连,写半包等场景进行处理,旨在理解 Reactor模型(多线程版本) 
 * @author dingwei2 
 * 
 */  
public class SubReactorThread extends Thread {

	private Selector selector;
	private ExecutorService businessExecutorPool;
	private List<NioTask> taskList = new ArrayList<NioTask>(512);
	private ReentrantLock taskMainLock = new ReentrantLock();

	/**
	 * 业务线程池
	 * @param businessExecutorPool
	 */
	public SubReactorThread(ExecutorService businessExecutorPool) {
		try {
			this.businessExecutorPool = businessExecutorPool;
			this.selector = Selector.open();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/**
	 * socket channel
	 * 
	 * @param socketChannel
	 */
	public void register(NioTask task) {
		if (task != null) {
			try {
				taskMainLock.lock();
				taskList.add(task);
			} finally {
				taskMainLock.unlock();
			}
		}
	}

	// private

	public void run() {
		while (!Thread.interrupted()) {
			Set<SelectionKey> ops = null;
			try {
				selector.select(1000);
				ops = selector.selectedKeys();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				continue;
			}

			// 处理相关事件
			for (Iterator<SelectionKey> it = ops.iterator(); it.hasNext();) {
				SelectionKey key = it.next();
				it.remove();

				try {
					if (key.isWritable()) { // 向客户端发送请求
						SocketChannel clientChannel = (SocketChannel) key
								.channel();
						ByteBuffer buf = (ByteBuffer) key.attachment();
						buf.flip();
						clientChannel.write(buf);
						System.out.println("服务端向客户端发送数据。。。");
						// 重新注册读事件
						clientChannel.register(selector, SelectionKey.OP_READ);
					} else if (key.isReadable()) { // 接受客户端请求
						System.out.println("服务端接收客户端连接请求。。。");
						SocketChannel clientChannel = (SocketChannel) key
								.channel();
						ByteBuffer buf = ByteBuffer.allocate(1024);
						System.out.println(buf.capacity());
						clientChannel.read(buf);//解析请求完毕
						
						//转发请求到具体的业务线程;当然,这里其实可以向dubbo那样,支持转发策略,如果执行时间短,
						//,比如没有数据库操作等,可以在io线程中执行。本实例,转发到业务线程池
						dispatch(clientChannel, buf);
						
					}
				} catch (Throwable e) {
					e.printStackTrace();
					System.out.println("客户端主动断开连接。。。。。。。");
				}

			}

			// 注册事件
			if (!taskList.isEmpty()) {
				try {
					taskMainLock.lock();
					for (Iterator<NioTask> it = taskList
							.iterator(); it.hasNext();) {
						NioTask task = it.next();
						try {
							SocketChannel sc = task.getSc();
							if(task.getData() != null) {
								sc.register(selector, task.getOp(), task.getData());
							} else {
								sc.register(selector, task.getOp());
							}
							
						} catch (Throwable e) {
							e.printStackTrace();// ignore
						}
						it.remove();
					}

				} finally {
					taskMainLock.unlock();
				}
			}

		}
	}
	
	/**
	 * 此处的reqBuffer处于可写状态
	 * @param sc
	 * @param reqBuffer
	 */
	private void dispatch(SocketChannel sc, ByteBuffer reqBuffer) {
		businessExecutorPool.submit( new Handler(sc, reqBuffer, this)  );
	}
}

NioTask,NIO相关任务封装类:

 

 

[java] view plain copy
 
print?
  1. package persistent.prestige.demo.netty.threadmode.t3;  
  2.   
  3. import java.io.Serializable;  
  4. import java.nio.channels.SocketChannel;  
  5.   
  6. /** 
  7.  * Nio task 
  8.  * @author Administrator 
  9.  * 
  10.  */  
  11. public class NioTask implements Serializable {  
  12.       
  13.     private SocketChannel sc;  
  14.     private int op;  
  15.     private Object data;  
  16.       
  17.     public NioTask(SocketChannel sc, int op) {  
  18.         this.sc = sc;  
  19.         this.op = op;  
  20.     }  
  21.       
  22.     public NioTask(SocketChannel sc, int op, Object data) {  
  23.         this(sc, op);  
  24.         this.data = data;  
  25.     }  
  26.     public SocketChannel getSc() {  
  27.         return sc;  
  28.     }  
  29.     public void setSc(SocketChannel sc) {  
  30.         this.sc = sc;  
  31.     }  
  32.     public int getOp() {  
  33.         return op;  
  34.     }  
  35.     public void setOp(int op) {  
  36.         this.op = op;  
  37.     }  
  38.     public Object getData() {  
  39.         return data;  
  40.     }  
  41.     public void setData(Object data) {  
  42.         this.data = data;  
  43.     }  
  44.       
  45.       
  46.   
  47. }  
package persistent.prestige.demo.netty.threadmode.t3;

import java.io.Serializable;
import java.nio.channels.SocketChannel;

/**
 * Nio task
 * @author Administrator
 *
 */
public class NioTask implements Serializable {
	
	private SocketChannel sc;
	private int op;
	private Object data;
	
	public NioTask(SocketChannel sc, int op) {
		this.sc = sc;
		this.op = op;
	}
	
	public NioTask(SocketChannel sc, int op, Object data) {
		this(sc, op);
		this.data = data;
	}
	public SocketChannel getSc() {
		return sc;
	}
	public void setSc(SocketChannel sc) {
		this.sc = sc;
	}
	public int getOp() {
		return op;
	}
	public void setOp(int op) {
		this.op = op;
	}
	public Object getData() {
		return data;
	}
	public void setData(Object data) {
		this.data = data;
	}
	
	

}
业务Handle类实现:

 

 

[java] view plain copy
 
print?
  1. package persistent.prestige.demo.netty.threadmode.t3;  
  2.   
  3. import java.nio.ByteBuffer;  
  4. import java.nio.channels.SelectionKey;  
  5. import java.nio.channels.SocketChannel;  
  6.   
  7. /** 
  8.  * 业务线程 
  9.  * 该handler的功能就是在收到的请求信息,后面加上 hello,服务器收到了你的信息,然后返回给客户端 
  10.  * @author Administrator 
  11.  * 
  12.  */  
  13. public class Handler implements Runnable {  
  14.       
  15.     private static final byte[] b = "hello,服务器收到了你的信息。".getBytes(); // 服务端给客户端的响应  
  16.       
  17.     private SocketChannel sc;  
  18.     private ByteBuffer reqBuffer;  
  19.     private SubReactorThread parent;  
  20.       
  21.     public Handler(SocketChannel sc, ByteBuffer reqBuffer,  
  22.             SubReactorThread parent) {  
  23.         super();  
  24.         this.sc = sc;  
  25.         this.reqBuffer = reqBuffer;  
  26.         this.parent = parent;  
  27.     }  
  28.   
  29.     public void run() {  
  30.         System.out.println("业务在handler中开始执行。。。");  
  31.         // TODO Auto-generated method stub  
  32.         //业务处理  
  33.         reqBuffer.put(b);  
  34.         parent.register(new NioTask(sc, SelectionKey.OP_WRITE, reqBuffer));  
  35.         System.out.println("业务在handler中执行结束。。。");  
  36.     }  
  37.   
  38. }  
package persistent.prestige.demo.netty.threadmode.t3;

import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;

/**
 * 业务线程
 * 该handler的功能就是在收到的请求信息,后面加上 hello,服务器收到了你的信息,然后返回给客户端
 * @author Administrator
 *
 */
public class Handler implements Runnable {
	
	private static final byte[] b = "hello,服务器收到了你的信息。".getBytes(); // 服务端给客户端的响应
	
	private SocketChannel sc;
	private ByteBuffer reqBuffer;
	private SubReactorThread parent;
	
	public Handler(SocketChannel sc, ByteBuffer reqBuffer,
			SubReactorThread parent) {
		super();
		this.sc = sc;
		this.reqBuffer = reqBuffer;
		this.parent = parent;
	}

	public void run() {
		System.out.println("业务在handler中开始执行。。。");
		// TODO Auto-generated method stub
		//业务处理
		reqBuffer.put(b);
		parent.register(new NioTask(sc, SelectionKey.OP_WRITE, reqBuffer));
		System.out.println("业务在handler中执行结束。。。");
	}

}

 

 

Nio客户端的实现,与上文一样。

 

注:本文代码旨在理解Reactor反应堆线程模型,对nio涉及到的断线重连,写半包等未做处理。本文关于Reactor模型的三个图片来源与网络,非原创,如果有侵权,请联系作者,将马上删除,谢谢。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics