java Socket简单聊天实现 —— 使用线程池及同步锁
2017-03-01 20:08
375 查看
现有的聊天室功能虽然已经完成,但是由于客户端的频繁连接与断开,会使得服务端频繁的创建及销毁线程。随着客户端的增加,服务端的线程也在增加,这无疑会对服务端的资源造成浪费,并且由于过多的线程导致的过度切换也会为服务端带来崩溃的风险。与此同时,多个线程会共享服务端的集合属性allOut,这里还存在着多线程并发的安全问题。
为此,需要重构聊天室案例,使用线程池技术来解决服务端多线程问题,并解决多线程并发的安全问题。
服务器端:需要在服务器端定义一个线程池类型的属性,用于管理服务端的线程创建及管理。修改Server的start方法,将原来创建并启动线程的代码替换为使用线程池管理的方式。然后在Server中添加三个方法,用于操作属性allOut,并使用同步锁,使三个方法变为同步的。
为此,需要重构聊天室案例,使用线程池技术来解决服务端多线程问题,并解决多线程并发的安全问题。
服务器端:需要在服务器端定义一个线程池类型的属性,用于管理服务端的线程创建及管理。修改Server的start方法,将原来创建并启动线程的代码替换为使用线程池管理的方式。然后在Server中添加三个方法,用于操作属性allOut,并使用同步锁,使三个方法变为同步的。
package TCPUDP; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Server { private ServerSocket serverSocket; //所有客户端输出流 private List<PrintWriter> allOut; //线程池 private ExecutorService threadPool; public Server(){ try{ serverSocket = new ServerSocket(8088); allOut = new ArrayList<PrintWriter>(); threadPool = Executors.newFixedThreadPool(40); }catch(Exception e){ e.printStackTrace(); } } /* * 将输出流存入共享集合,与下面两个方法互斥,保证同步安全 */ private synchronized void addOut(PrintWriter out){ allOut.add(out); } private synchronized void removeOut(PrintWriter out){ allOut.remove(out); } private synchronized void sendMessage(String message){ for(PrintWriter o:allOut){ o.println(message); } } /* * 线程体:用于并发处理不同客户端的交互 * */ class ClientHandler implements Runnable{ private Socket socket; //构造函数设置为public public ClientHandler(Socket socket){ this.socket = socket; } @Override public void run() { PrintWriter pw = null; try { OutputStream os = socket.getOutputStream(); OutputStreamWriter osw = new OutputStreamWriter(os, "UTF-8"); pw = new PrintWriter(osw, true); //存入共享集合 //allOut.add(pw); addOut(pw); InputStream is = socket.getInputStream(); InputStreamReader isr = new InputStreamReader(is, "UTF-8"); BufferedReader br = new BufferedReader(isr); String message = null; while((message = br.readLine()) != null){ //for(PrintWriter o: allOut){ // o.println(message); sendMessage(message); } }catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); }finally{ //当客户端断线时,要将输出流从集合中删除 //allOut.remove(pw); removeOut(pw); if(socket != null){ try{ socket.close(); }catch(Exception e){ e.printStackTrace(); } } } } } public void start(){ try{ //循环监听客户端的连接 while(true){ System.out.println("等待客户端连接。。。"); Socket socket = serverSocket.accept(); System.out.println("客户端已连接!"); ClientHandler handler = new ClientHandler(socket); //启动一个线程来完成针对该客户端的交互 threadPool.execute(handler); } }catch(Exception e){ e.printStackTrace(); } } public static void main(String[] args) { // TODO Auto-generated method stub Server server = new Server(); server.start(); } }客户端:
package TCPUDP; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.Socket; import java.util.Scanner; public class Client { private Socket socket; public Client(){ try { socket = new Socket("localhost", 8088); } catch (Exception e) { e.printStackTrace(); } } private class ServerHandler implements Runnable{ @Override public void run() { // TODO Auto-generated method stub try{ InputStream is = socket.getInputStream(); InputStreamReader isr = new InputStreamReader(is, "UTF-8"); BufferedReader br = new BufferedReader(isr); while(true){ System.out.println(br.readLine()); } }catch(Exception e){ e.printStackTrace(); } } } public void start(){ try{ ServerHandler handler = new ServerHandler(); Thread t = new Thread(handler); t.setDaemon(true); t.start(); OutputStream out = socket.getOutputStream(); OutputStreamWriter osw = new OutputStreamWriter(out, "UTF-8"); PrintWriter pw = new PrintWriter(osw, true); //创建Scanner读取用户输入内容 Scanner scanner = new Scanner(System.in); while(true){ pw.println(scanner.nextLine()); } }catch(Exception e){ e.printStackTrace(); }finally{ if(socket != null){ try{ socket.close(); }catch(Exception e){ e.printStackTrace(); } } } } public static void main(String[] args) { // TODO Auto-generated method stub Client client = new Client(); client.start(); } }
相关文章推荐
- 使用Java Socket实现简单的聊天功能
- 使用Beetle.NetPackage简单实现android和wp聊天
- IOS开发之使用Speex格式实现简单的语音聊天功能(一)
- java Socket实现简单在线聊天(二)
- 使用C++11实现一个半同步半异步线程池
- 使用RecyclerView实现简单的聊天页面
- 使用common-pool实现的一个简单的线程池
- 初学Java Socket,实现超简单的聊天程序
- iOS 使用XMPP框架开发IM聊天模块,实现简单的文字聊天
- java Socket实现简单在线聊天(三)
- 使用C++实现简单线程池v1.0
- 使用C++实现简单线程池v1.0
- Java中使用synchronized关键字实现简单同步操作示例
- java Socket实现简单在线聊天(一)
- Spring+JMS+使用JMS+ActiveMQ中间件+实现简单聊天功能的小例子
- 使用common-pool实现的一个简单的线程池
- 使用Ajax long polling实现简单的聊天程序
- IOS开发之使用Speex格式实现简单的语音聊天功能(一)
- 使用Express + Socket.io + MongoDB实现简单的聊天
- 使用Socket、SeverSocket,利用线程实现的简单的一对一聊天