前文曾经讲到,如何使用多线程机制分派应答线程,但是该实现在使用loadRunner测试的时候,发现系统在并发访问是内存占用非常大,在一段时间的测试后虚拟机报告not enough memory的错误。当然,我们可以通过增加虚拟机参数设置的方法,增加虚拟机最大内存占用值,但是一旦系统所需的内存超过设定值,虚拟机依然会报错。
幸运的是,java 6提供java.util.concurrent.Executors类对线程池进行控制。
我们对Myserver类进行如下修改:
其实我仅仅修改了两句代码
pool = Executors.newFixedThreadPool(50);
和
pool.execute(pc);
头一句做了一个固定大小的线程池,第二句执行
当然我们也可以pool = Executors.newCachedThreadPool();这样仅仅建立一个普通的线程池,线程可以重用,但是没有数量限制....
幸运的是,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();这样仅仅建立一个普通的线程池,线程可以重用,但是没有数量限制....