知识大全 使用JAVA建立稳定的多线程服务器
Posted 知
篇首语:宁死不背理,宁贫不堕志。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 使用JAVA建立稳定的多线程服务器相关的知识,希望对你有一定的参考价值。
使用JAVA建立稳定的多线程服务器 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!
本文详细的介绍了使用Java语言建立一套多线程服务器的过程 该服务器使用对象传递消息 在线程中使用队列机制 使服务器的性能大大提高了 这套服务器可以被用于各种C/S或B/S结构的应用程序中Java语言是完全面向对象的 它的线程机制和对象序列化特别容易使用 使用Java来建立一套多线程服务器要比使用其它语言方便的多 如果你再把它的异常处理机制利用好 那么你就可以建立一个商业级的多线程服务器了 由于采用了消息队列和Socket传输方式 所以不会出现丢消息的问题 这套服务器可以作为实时聊天服务器 多人协同的协作服务器等等
消息系统的建立
这套服务器的消息系统采用的是对象传输的机制 而不是以前常常使用的字符串传输 采用对象传输的好处是扩展方便 如需要建立一个新的消息只需要从一个统一的基类继承下来 然后再写自己实现的方法就行了 这样也符合面向对象领域里一条重要的原则 OCP(open_closed Principle) 即一个好的设计应该能够容纳新的功能的增加 但是增加的方式不是修改原有的类 而是添加新的类
首先建立一个基类 Msg 该抽象类中有两个域sender和receiver分别纪录消息的发送者和接收者 这两个域是在构造消息类时就填写的 receiver域可以为空 空表示发给谁都可以 由转发服务器来决定 该类的方法包括取得这两个域的值和消息的处理函数 消息的处理函数process()是空函数 供继承者重载
建立了这个抽象基类后 你就可以继承它完成你自己的类 举个例子 假如我要建立一个分组协同工作的绘图系统 而且支持组员之间的对话 那么我可以建立如下的类集合
SendTextMsg(String sender String receiver String info)//向指定的人发送对话
AddLineMsg(String sender Point a Point b)//在指定的点之间绘制一条直线
AddRectangle(String sender point start Point end)//建立指定的矩形
AddRotundaMsg(String sender Point center int radius)//建立指定的圆
RemoveObjectMsg(String sender int ID)//删除指定编号的图形对象
……
以此类推 可以建立很多的消息类 在每个类的内部都由一个处理该类的方法process() 填写该方法就可以实现对消息类的处理 而服务器只负责完成消息的转发功能 这样 一套消息系统就建立了
服务器的结构
如果要服务器实现同时为每个客户端服务 就要使用多线程 建立一个线程池 当有客户端连接时就在池中开辟一个线程为它服务 同样 要避免大量消息到达时处理不过来而导致丢失的情况 就要使用消息队列 这个服务器是分层的处理的
服务器的工作过程是这样的 建立了一个Server类作为主类 它含有程序的入口函数main() 在构造函数中初始化一个数组存放ClientSingle类 它其实就是单独处理一个连接用户的类 然后启动一个线程PORTListenThread 该线程的作用就是监听端口上有没有人登陆 当有人连接时交给Server的addClient()处理 Server的addClient()方法会在刚才那个数组中建立一个ClientSingle对象 然后把剩下的事都交给它做
端口监听线程类PORTListenThread
该线程类在run()函数的开始部分首先要检查serverScoket是否为空 保证循环开始时不要出错 然后进入一个死循环的监听
while(true) //死循环监
trySocket clientSocket=null;
clientSocket=serverSocket accept();
server addClient(clientSocket);//转交Server处理
catch (IOException e)System out println( 监听端口时出错 +e);//显示错误
单个客户端在连接池中的映像类ClientSingle
每一个客户端连接到服务器后 服务器会自动在连接池中建立该客户端的一个映像 所有的操作都交给这个映像去具体执行 所以ClientSingle中一定要包含客户端的一些基本的信息 比如客户端的名称 登陆时间等等 在该类中有两个消息队列sendQueue(发送队列)和receiveQueue(接收队列)缓存消息
ClientSingle类是继承自Thread的 它还是一个调用者 在初始化的时候启动两个子线程类SingleSender和SingleListener运行 SingleSender负责监听指令发送队列中有没有指令 有则发送 SingleListener负责监听有没有消息到达 有则把这些消息加入到接收队列中去 由ClientSingle处理 所以ClientSingle的主要任务就是对这两个队列的处理 这两个队列可以用Vector实现 非常地简单
// 将消息加入发送队列中
synchronized void send(Object o) sendQueue add(o);
为了稳定控制子线程的运行 并不鼓励在run()方法的死循环标志都用true 而是使用了一个布尔型的变量finish 外部可以通过把这个标志置为假而停止线程的运行
发送子线程类启动后执行run()中的循环(以finish为结束标志) 在该循环内首先判断ClientSingle中的发送队列是否为空 为空时睡眠一定的时间再重新判断 这也是一个while循环 不为空则开始处理队列中的消息 把它取出后放入输出流中发送
public void run()
while (!father finish) //循环监听
while(father v isEmpty()) //当发送队列为空的时候线程睡眠 毫秒
tryThread sleep( );
catch(InterruptedException e)System out println(e);
if (!father v isEmpty()) //发送队列不为空时
try
Object a=father v firstElement();//取出队列中的第一个消息
father v removeElementAt( );//从队列中删除
oos writeObject(a);//发送该消息
oos flush();
catch(IOException e)
displayMessage( 传输失败 ! );
father finish=false;
接收子线程SingleListener类和发送子线程是类似的 它们的run()方法都差不多 不同的是接收子线程把收到的消息加入到ClientSingle的接收队列中去 由它处理
ClientSingle类的run()方法就在循环地读取接收队列receiveQueue中的内容 为空时等待 不为空时依次取出处理和转发 处理消息的函数是processMsg() 它只是执行消息类自己的process()方法罢了 在处理完后 会调用Server类的方法进行各种类型的转发
分组转发的实现类Group
为了实现对客户端分组 我建立了Group类 在这个类中有一个列表存放已经存在于连接池中的那些ClientSingle类的引址 只要遍历整个列表就能访问所有组中的成员 这个列表可以用Vector实现 也可以用哈希表 我推荐后者 主要是为了能够按名字存取
组对象本身也是可以存在Server类的组列表中的
分组功能对多人的协同系统来说是非常重要的 特别是分组对某一个共享空间操作的时候 就以上面的协同绘图系统为例 如果 个人里有三个人要另起炉灶 那么他们三个的画板就不能让其他人看到 这就必须有 组 个划分
主服务器类Server
Server类是最核心的类 它在这个框架中起到调度全局的作用 上面介绍的那些类都由它来统一的构造和调用
Server类的域包括一个定长的数组存放ClientSingle实例 它就是连接池的实现 还要有一个哈希表存放Group实例 Server类的方法都是对这两个类的操作
建立ClientSingle数组的目的是保证服务器的稳定性 其实 你也可以选择不建立它 只是动态地构造对象 但是那样不好管理连接的用户 而且由于各种操作系统对进程的处理不同 动态建立服务线程会很不稳定 所以我先建立一个数组作为这些对象的容器 在开始时就估计好连接者的最大数量 Server类的addClient()函数
void addClient(Socket socket)
int c= ;
trywhile (sch[c]!=null) C++;//搜索数组中的空余空间
catch(ArrayIndexOutOfBoundsException e)
try socket close();//出现异常关闭槽连接
catch(IOException ee) System out println( 数组溢出 );
return;
sch[c]=new ClientSingle(c socket father this);//在搜索到的位置建立ClientSingle对象
Server类中转发的方法有 sendToAll() sendToOne() sendToGroup()等等 这些方法都是对线程池中的方法的操作 比较简单 不外乎都是找到线程池中的某个ClientSingle对象 然后调用它的send()方法罢了
注意 这些转发的方法可能被很多子线程同时调用 所以为了保持线程的稳定 千万记住要在方法前加synchronized关键字
总结
cha138/Article/program/Java/gj/201311/27736相关参考
Java的多线程-实现多线程及线程的同步 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 一.实现
解析Java的多线程机制 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 一进程与应用程序的区别
Java程序中的多线程 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 一为什么会排队等待? 下
Java程序中的多线程(四) 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 作者NeelVKum
Java程序中的多线程(二) 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 作者NeelVKum
Java程序中的多线程(一) 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 作者NeelVKum
最近写了一个HTTP代理服务器发现访问网页时建立的连接很多消耗的线程也非常的多对于系统是一个不小的开销而且这些线程存在的时间都很短%以上的线程存在的时间
用Java实现多线程服务器程序 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 摘要在Java出现
JavaSocket多线程如何支持服务器模型 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! Ja
JavaSocket多线程服务端、客户端 以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! //主方