Scalable IO in Java的代码实现


        最近在学习NIO相关的知识部分,在学习的时候,发现Doug Lea大神的一个PPT地址,里面的内容写的非常好,

很值得学习,具体内容可以参见PPT和网上的文章,自己根据PPT中的例子和描述,自己将代码补充了一下。下面主要是PPT中的代码和实例。

1.Basic Reactor Design


package basic;

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;
/**
* @ClassName: Reactor
* @Description: 根据 Scalable IO in Java写的实例。
* @date 2017年3月7日
 */
public class Reactor implements Runnable
{
	final Selector selector;
	final ServerSocketChannel serverSocketChannel;
	public Reactor(int port) throws IOException
	{
		selector = Selector.open();
		serverSocketChannel = ServerSocketChannel.open();
		serverSocketChannel.socket().bind(new InetSocketAddress(port));
		serverSocketChannel.configureBlocking(false);
		SelectionKey key = serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
		key.attach(new Acceptor());
	}
	public void run()
	{
		try{
			while(!Thread.interrupted()){
				int n = selector.select();//等待事件
				if(n == 0)
					continue;
				Set<SelectionKey> set = selector.selectedKeys();
				Iterator<SelectionKey> iterator = set.iterator();
				while(iterator.hasNext()){
					dispatch(iterator.next());
				}
				set.clear();
			}
		}catch(Exception e){
			e.printStackTrace();
		}
	}
	private void dispatch(SelectionKey k)
	{
		Runnable runnable = (Runnable) k.attachment();
		if(runnable != null)
			runnable.run();
	}
	class Acceptor implements Runnable
	{
		public void run()
		{
			try
			{
				SocketChannel c = serverSocketChannel.accept();//接收请求
				if(c != null){
					System.out.println("New Connection ...");
					new Handler(selector, c);
				}
			} catch (IOException e)
			{
				e.printStackTrace();
			}
		}
	}
	
	final class Handler implements Runnable{
		
		final SocketChannel socket;
		final SelectionKey key;
		ByteBuffer input = ByteBuffer.allocate(1024);
		ByteBuffer output = ByteBuffer.allocate(1024);
		static final int READING = 0,SENDING =1;
		int state = READING;
		
		public Handler(Selector selector, SocketChannel c) throws IOException
		{
			socket = c;
			socket.configureBlocking(false);
			key = socket.register(selector, 0);
			key.attach(this);
			key.interestOps(SelectionKey.OP_READ);//注册可读事件
			selector.wakeup();
		}
		public void run()
		{
			try {
				if(state == READING)
					read();
				else if(state == SENDING)
					send();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		boolean inputIsComplete(){
			return input.hasRemaining();
		}
		boolean outputIsComplete(){
			return output.hasRemaining();
		}
		void process(){
			//读数据
			StringBuilder reader = new StringBuilder();
			input.flip();
			while(input.hasRemaining()){
				reader.append((char)input.get());
			}
			System.out.println("[Client-INFO]");
			System.out.println(reader.toString());
			String str = "HTTP/1.1 200 OK\r\nDate: Fir, 10 March 2017 21:20:01 GMT\r\n"+
					"Content-Type: text/html;charset=UTF-8\r\nContent-Length: 23\r\nConnection:close"+
					"\r\n\r\nHelloWorld"+System.currentTimeMillis();
			output.put(str.getBytes());
			System.out.println("process over.... ");
		}
		void read() throws IOException{
			socket.read(input);
			if(inputIsComplete()){
				process();
				state = SENDING;
				key.interestOps(SelectionKey.OP_WRITE);
			}
		}
		void send() throws IOException {
			output.flip();
			socket.write(output);
			if(outputIsComplete()){
				key.cancel();
			}
			state = READING;
			key.interestOps(SelectionKey.OP_READ);
		}
	} 
	public static void main(String[] args) throws IOException
	{
		new Thread(new Reactor(9001)).start();
		System.out.println("Server start...");
	}
}


2.Per-State Handlers

package state;

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;
/**
* @ClassName: Reactor
* @Description: 根据 Scalable IO in Java写的实例。
* @author Lzyer
* @date 2017年3月7日
 */
public class Reactor implements Runnable
{
	final Selector selector;
	final ServerSocketChannel serverSocketChannel;
	public Reactor(int port) throws IOException
	{
		selector = Selector.open();
		serverSocketChannel = ServerSocketChannel.open();
		serverSocketChannel.socket().bind(new InetSocketAddress(port));
		serverSocketChannel.configureBlocking(false);
		SelectionKey key = serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
		key.attach(new Acceptor());
	}
	public void run()
	{
		try{
			while(!Thread.interrupted()){
				int n = selector.select();//等待事件
				if(n == 0)
					continue;
				Set<SelectionKey> set = selector.selectedKeys();
				Iterator<SelectionKey> iterator = set.iterator();
				while(iterator.hasNext()){
					dispatch(iterator.next());
				}
				set.clear();
			}
		}catch(Exception e){
			e.printStackTrace();
		}
	}
	private void dispatch(SelectionKey k)
	{
		Runnable runnable = (Runnable) k.attachment();
		if(runnable != null)
			runnable.run();
	}
	class Acceptor implements Runnable
	{
		public void run()
		{
			try
			{
				SocketChannel c = serverSocketChannel.accept();
				if(c != null){
					System.out.println("New Connection ...");
					new Handler2(selector, c);
				}
			} catch (IOException e)
			{
				e.printStackTrace();
			}
		}
	}
	
	/***
	* @ClassName: Handler2
	* @Description: State-Object pattern
	* @author lzyer 
	* @date 2017年3月8日
	*
	 */
	class Handler2 implements Runnable{
		
		final SocketChannel socket;
		final SelectionKey key;
		ByteBuffer input = ByteBuffer.allocate(1024);
		ByteBuffer output = ByteBuffer.allocate(1024);
		static final int READING = 0,SENDING =1;
		int state = READING;
		
		public Handler2(Selector selector, SocketChannel c) throws IOException
		{
			this.socket = c;
			this.socket.configureBlocking(false);
			key  = socket.register(selector, SelectionKey.OP_READ);
			key.attach(this);
			selector.wakeup();
		}
		
		public void run()
		{
			try
			{
				socket.read(input);
				if(inputIsComplete()){
					process();
					key.attach(new Sender());//send thread
					key.interestOps(SelectionKey.OP_WRITE);
					key.selector().wakeup();
				}
			} catch (IOException e)
			{
				e.printStackTrace();
			}
		}
		boolean inputIsComplete(){
			return input.hasRemaining();
		}
		boolean outputIsComplete(){
			return output.hasRemaining();
		}
		void process(){
			//读数据
			StringBuilder reader = new StringBuilder();
			input.flip();
			while(input.hasRemaining()){
				reader.append((char)input.get());
			}
			System.out.println("[Client-INFO]");
			System.out.println(reader.toString());
			String str = "HTTP/1.1 200 OK\r\nDate: Sat, 31 Dec 2005 23:59:59 GMT\r\n"+
					"Content-Type: text/html;charset=UTF-8\r\nContent-Length: 23\r\nConnection:close"+
					"\r\n\r\nWelcome NIO "+System.currentTimeMillis();
			output.put(str.getBytes());
			System.out.println("process over.... ");
		}
		class Sender implements Runnable{
			
			public void run()
			{
				try
				{
					output.flip();
					socket.write(output);
					if(outputIsComplete())
						key.cancel();
					socket.close();//记住要关闭
				} catch (IOException e)
				{
					e.printStackTrace();
				}
				
			}
		}
	}
	public static void main(String[] args) throws IOException
	{
		new Thread(new Reactor(9001)).start();
		System.out.println("Server start...");
	}
}


3.Handler with Thread Pool


package pool;

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;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @ClassName: Reactor
* @Description: 根据 Scalable IO in Java写的实例。
* @author Lzyer 
* @date 2017年3月7日
 */
public class Reactor implements Runnable
{
	final Selector selector;
	final ServerSocketChannel serverSocketChannel;
	public Reactor(int port) throws IOException
	{
		selector = Selector.open();
		serverSocketChannel = ServerSocketChannel.open();
		serverSocketChannel.socket().bind(new InetSocketAddress(port));
		serverSocketChannel.configureBlocking(false);
		SelectionKey key = serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
		key.attach(new Acceptor());
	}
	public void run()
	{
		try{
			while(!Thread.interrupted()){
				int n = selector.select();
				if(n == 0)
					continue;
				Set<SelectionKey> set = selector.selectedKeys();
				Iterator<SelectionKey> iterator = set.iterator();
				while(iterator.hasNext()){
					dispatch(iterator.next());
				}
				set.clear();
			}
		}catch(Exception e){
			e.printStackTrace();
		}
	}
	private void dispatch(SelectionKey k)
	{
		Runnable runnable = (Runnable) k.attachment();
		if(runnable != null)
			runnable.run();
	}
	class Acceptor implements Runnable
	{
		public void run()
		{
			try
			{
				SocketChannel c = serverSocketChannel.accept();
				if(c != null){
					System.out.println("New Connection ...");
					new Handler3(selector, c);
				}
			} catch (IOException e)
			{
				e.printStackTrace();
			}
		}
	}
	
	/**
	* @ClassName: Handler3
	* @Description: 使用线程池
	* @author Lzyer 
	* @date 2017年3月8日
	*
	 */
	class Handler3 implements Runnable
	{
		final SocketChannel socket;
		final SelectionKey key;
		ByteBuffer input = ByteBuffer.allocate(1024);
		ByteBuffer output = ByteBuffer.allocate(1024);
		static final int READING = 0,SENDING =1, PROCESSING =3;
		int state = READING;
		ExecutorService pool = Executors.newCachedThreadPool();
		public Handler3(Selector selector, SocketChannel c) throws IOException
		{
			this.socket = c;
			this.socket.configureBlocking(false);
			key = socket.register(selector, SelectionKey.OP_READ);
			key.attach(this);
			selector.wakeup();
		}
		public void run()
		{
			try
			{
				if(state == READING)
					read();
				else if(state == SENDING)
					send();
			} catch (IOException e)
			{
				e.printStackTrace();
			}
		}
		synchronized void read() throws IOException { 
			socket.read(input);
			if (inputIsComplete()) {
				state = PROCESSING;
				pool.execute(new Processer());
			}
		}
		void send() throws IOException {
			output.flip();
			socket.write(output);
			if(outputIsComplete()){
				key.cancel();
			}
			state = READING;
			key.interestOps(SelectionKey.OP_READ);
		}
		void process(){
			//读数据
			StringBuilder reader = new StringBuilder();
			input.flip();
			while(input.hasRemaining()){
				reader.append((char)input.get());
			}
			System.out.println("[Client-INFO]");
			System.out.println(reader.toString());
			String str = "HTTP/1.1 200 OK\r\nDate: Fir, 10 March 2017 21:20:01 GMT\r\n"+
					"Content-Type: text/html;charset=UTF-8\r\nContent-Length: 32\r\nConnection:close"+
					"\r\n\r\nWelcome JAVA World "+System.currentTimeMillis();
			output.put(str.getBytes());
			System.out.println("process .... ");
		}
		boolean inputIsComplete(){
			return input.hasRemaining();
		}
		boolean outputIsComplete(){
			return output.hasRemaining();
		}
		synchronized void processAndHandOff() {
			process();
			state = SENDING; // or rebind attachment
			key.interestOps(SelectionKey.OP_WRITE);
			System.out.println("processer over....");
		}
		class Processer implements Runnable
		{
			public void run()
			{
				processAndHandOff();
			}
		}
	}
	public static void main(String[] args) throws IOException
	{
		new Thread(new Reactor(9001)).start();
		System.out.println("Server start...");
	}
}


4Using Multiple Reactors


package multiple;

import java.io.IOException;
import java.util.concurrent.atomic.AtomicInteger;

public class Server
{
	private static Reactor mainReactor;//主要负责接收请求
	private static Reactor[] subReactors;//负责处理IO
	private static final int SUB_SIZE = 3;
	private static final int port = 1234;
	
	private static AtomicInteger nextIndex = new AtomicInteger();
	
	public static Reactor nextSubReactor(){
		long nextIndexValue = nextIndex.getAndIncrement();
		if(nextIndexValue < 0){
			nextIndex.set(0);
			nextIndexValue = 0;
		}
		return subReactors[(int) (nextIndexValue%subReactors.length)];
	}
	
	public static void main(String[] args)
	{
		try
		{
			mainReactor = new Reactor(port, true);
			subReactors = new Reactor[SUB_SIZE];
			for(int i=0; i< subReactors.length; i++){
				subReactors[i] = new Reactor(port, false);
			}
			mainReactor.start();
			for(int i=0; i< subReactors.length; i++){
				subReactors[i].start();
			}
		} catch (IOException e)
		{
			e.printStackTrace();
		}
	}
}


package multiple;

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.util.Iterator;

/**
* @ClassName: Reactor
* @Description: 根据 Scalable IO in Java写的实例。
* @author Lzyer 
* @date 2017年3月10日
 */
public class Reactor extends Thread
{
	final Selector selector;
	final boolean isMain;//主从的标志
	
	public Reactor(int port, boolean isMain) throws IOException
	{
		this.isMain = isMain;
		selector = Selector.open();
		System.out.println(selector +" isMainReactor = "+isMain);
		if(isMain){
			ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
			serverSocketChannel.socket().bind(new InetSocketAddress(port));
			serverSocketChannel.configureBlocking(false);
			SelectionKey key = serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
			key.attach(new Acceptor(selector, serverSocketChannel));
			selector.wakeup();
			System.out.println(getClass().getSimpleName()+" start on "+port+" ...\n");
		}
	}
	public void run()
	{
		try
		{
			while(!Thread.interrupted()){
				int n = selector.select(10);//会阻塞导致不能register,设置阻塞时间
				if(n == 0)
					continue;
				Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
				while(iterator.hasNext()){
					dispatch(iterator.next());
					iterator.remove();
				}
			}
		} catch (IOException e)
		{
			e.printStackTrace();
		}
	}
	private void dispatch(SelectionKey k)
	{
		Runnable runnable = (Runnable) k.attachment();
		if(runnable != null)
			runnable.run();
	}

}


package multiple;

import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;

/**
* @ClassName: Acceptor
* @Description: 接收请求
* @author Lzyer 
* @date 2017年3月9日
*
 */
public class Acceptor implements Runnable
{
	private ServerSocketChannel serverSocketChannel;
	
	private Selector selector;
	
	public Acceptor(Selector selector,ServerSocketChannel ser)
	{
		this.selector = selector;
		this.serverSocketChannel = ser;
	}
	public void run()
	{
		try{
			System.out.println(selector+"  accept ....");
			
			SocketChannel socketChannel = serverSocketChannel.accept();
			if(socketChannel != null){
				/**
				 *  开启了多个reactor池,一个selector负责接收和处理IO
				 * new Handler(selector, socketChannel);
				 */
				//使用的主从结构,一个主selector负责接收,其他的负责处理IO
				Selector selector2 = Server.nextSubReactor().selector;
				System.out.println(selector2+" clientChannel not null..."+socketChannel);
				new Handler(selector2, socketChannel);
			}
		}catch(Exception e){
			e.printStackTrace();
		}
	}
}


package multiple;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
/**
* @ClassName: Handler
* @Description: 处理IO操作
* @author Lzyer 
* @date 2017年3月9日
*
 */
public class Handler implements Runnable
{
	final SocketChannel socket;
	final SelectionKey key;
	ByteBuffer input = ByteBuffer.allocate(1024);
	ByteBuffer output = ByteBuffer.allocate(1024);
	static final int READING = 0,SENDING =1;
	int state = READING;
	
	public Handler(Selector selector, SocketChannel c) throws IOException
	{
		socket = c;
		socket.configureBlocking(false);
		key = socket.register(selector,SelectionKey.OP_READ);
		key.attach(this);
		selector.wakeup();
		System.out.println(selector+" connect success...");
	}
	public void run()
	{
		try {
			if(state == READING)
				read();
			else if(state == SENDING)
				send();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	boolean inputIsComplete(){
		return input.hasRemaining();
	}
	boolean outputIsComplete(){
		return output.hasRemaining();
	}
	void process(){
		//读数据
		StringBuilder reader = new StringBuilder();
		input.flip();
		while(input.hasRemaining()){
			reader.append((char)input.get());
		}
		System.out.println("[Client-INFO]");
		System.out.println(reader.toString());
		String str = "HTTP/1.1 200 OK\r\nDate: Fir, 10 March 2017 21:20:01 GMT\r\n"+
				"Content-Type: text/html;charset=UTF-8\r\nContent-Length: 24\r\nConnection:close"+
				"\r\n\r\nHelloRector"+System.currentTimeMillis();
		output.put(str.getBytes());
		System.out.println("process .... ");
	}
	void read() throws IOException{
		socket.read(input);
		if(inputIsComplete()){
			process();
			state = SENDING;
			key.interestOps(SelectionKey.OP_WRITE);
		}
	}
	void send() throws IOException {
		output.flip();
		socket.write(output);
		if(outputIsComplete()){
			key.cancel();
		}
		state = READING;
		key.interestOps(SelectionKey.OP_READ);
	}

}


代码地址:链接

参考:http://blog.csdn.net/jjzhk/article/details/39553613

       http://www.iclojure.com/blog/articles/2015/12/05/Scalable-IO-in-Java


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值