fried cake server ----我的油炸糕(4)并发机制的改造

前文曾经讲到,如何使用多线程机制分派应答线程,但是该实现在使用loadRunner测试的时候,发现系统在并发访问是内存占用非常大,在一段时间的测试后虚拟机报告not enough memory的错误。当然,我们可以通过增加虚拟机参数设置的方法,增加虚拟机最大内存占用值,但是一旦系统所需的内存超过设定值,虚拟机依然会报错。
幸运的是,java 6提供java.util.concurrent.Executors类对线程池进行控制。
我们对Myserver类进行如下修改:
public class MyServer
{
	public static final int setTimeOut = 8000;

	private  int port = 80;//默认端口

	Selector selector;
	ByteBuffer buffer = ByteBuffer.allocate(1024 * 8);
	private final ExecutorService pool;
	/**
	 * 初始化一个server
	 * @throws Exception
	 */
	public  MyServer() throws Exception
	{
		pool = Executors.newFixedThreadPool(50);
		init();
	}
	/**
	 * 实际初始化一个server
	 * 包括webLoader加载、解析appRuntime、注册通道等工作
	 * @throws Exception
	 */
	public void init() throws Exception
	{
		/*初始化webloader*/
		WebLoader webLoader = WebLoader.getInstance();
		webLoader.loadAll();// 这里已经隐含着将appRuntime初始化了
		port = (Integer)AppRunTime.getInstance().getProperty(Constant.SERVER_PORT); 
		ServerSocketChannel channel = ServerSocketChannel.open();
		channel.configureBlocking(false);
		channel.socket().bind(new InetSocketAddress(port));
		selector = Selector.open();
		channel.register(selector, SelectionKey.OP_ACCEPT);
	}

	/**
	 * 请不要误会,这并不是一个多线程的run()方法
	 * 另外,server只接受isAcceptable为真的请求
	 * 单向的消息请求暂不提供
	 * @throws Exception
	 */
	public void run() throws Exception
	{
		while (true)
		{
			int num = selector.select();
			if (num != 0)
			{
				Set<SelectionKey> set = selector.selectedKeys();
				Iterator<SelectionKey> it = set.iterator();

				while (it.hasNext())
				{
					SelectionKey key = it.next();

					if (key.isAcceptable())
					{
						accept((ServerSocketChannel) key.channel());
					}
					it.remove();
				}
			}
		}

	}
	
	
    /**
     * 对于isAcceptable的请求启动一个SoketProcess线程
     * @param serverSocket
     * @throws IOException
     */
	protected void accept(ServerSocketChannel serverSocket) throws IOException
	{
		SocketProcess pc = new SocketProcess(serverSocket);
		/*使用java1.6的多线程新特性*/
		pool.execute(pc);
		/*测试用*/
		//pc.run();
	}

    /**
     * 启动命令,发布版里使用bootstrap项目调用这个main方法,参数设置也挪至bootstrap项目中
     * @param args 暂无 待扩充
     * @throws Exception
     */
	public static void main(String args[]) throws Exception
	{
		long time = Calendar.getInstance().getTimeInMillis();
		MyServer server = new MyServer();
		time = Calendar.getInstance().getTimeInMillis()-time;
		System.out.println("服务器这正在监听端口"+AppRunTime.getInstance().getProperty(Constant.SERVER_PORT)+".....");
		System.out.println("启动成功,总耗时"+time+"毫秒.....");
		server.run();
	}
}

其实我仅仅修改了两句代码
pool = Executors.newFixedThreadPool(50);

pool.execute(pc);
头一句做了一个固定大小的线程池,第二句执行
当然我们也可以pool = Executors.newCachedThreadPool();这样仅仅建立一个普通的线程池,线程可以重用,但是没有数量限制....

你可能感兴趣的:(多线程,工作,虚拟机,socket,loadrunner)