服务端代码
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
class ServerOneThread extends Thread{
private static Map<Socket,String> messageMap = new HashMap<Socket,String>();
private static Map<Socket,InetAddress> socketMap = new HashMap<Socket,InetAddress>();
private static File file = new File("TalkLog.txt");
private BufferedReader in;
private PrintWriter out;
private Socket socket;
private FileWriter fWriter;
public ServerOneThread(Socket socket) throws IOException {
this.socket = socket;
socketMap.put(socket, socket.getInetAddress());
System.out.println(Thread.currentThread()+"----------------------socketMap添加"+"第"+socketMap.size()+"个"+socket);
in = new BufferedReader(
new InputStreamReader(this.socket.getInputStream()));
// out = new PrintWriter(
// new BufferedOutputStream(this.socket.getOutputStream()),true);
fWriter = new FileWriter(file,true);
start();
}
@Override
public void run() {
try{
while(true){
String str = in.readLine();
if(!str.isEmpty()){
if(str.equals("END"))break;
}
messageMap.put(socket,str+"");
fWriter.write("\n"+socket+str+"\n\n");//把客户地址和发送的数据保存
fWriter.flush();
System.out.println(socket.getInetAddress().getHostName()+"的输入:"+str);
//防止多线程同时访问一个map,把map复制一份到一个临时的map中
// Map<Socket,InetAddress> tempMap = new HashMap<Socket,InetAddress>();
// synchronized (socketMap) {
//
// tempMap.putAll(socketMap);//多线程下这个复制时不安全的
// }
// for (Socket toSocket : tempMap.keySet()) {
// out = new PrintWriter(
// new BufferedOutputStream(toSocket.getOutputStream()),true);
// out.println(toSocket.getInetAddress().getHostName()+" 说: "+messageMap.get(socket));
// }
synchronized (socketMap) {
Iterator<Socket> it = socketMap.keySet().iterator();
while(it.hasNext()){
System.out.println(Thread.currentThread()+"----------------------有下一个元素");
Socket s = it.next();
System.out.println(Thread.currentThread()+"----------------------socketMap迭代socket:"+s);
out = new PrintWriter(
new BufferedOutputStream(s.getOutputStream()),true);
out.println(s.getInetAddress().getHostName()+" 说: "+messageMap.get(socket));
}
}
}
}catch(IOException e){
System.out.println(e);
}
finally{
try {
socket.close();
fWriter.close();
socketMap.remove(socket);
} catch (IOException e) {
System.out.println("socketMap remove()"+e);;
}
}
}
}
public class JavaMultiThreadServerSocket{
private static final int PORT = 8080;
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(PORT);
System.out.println("创建ServerSocket: "+serverSocket);
try{
while(true){
Socket s = serverSocket.accept();
System.out.println("连接客户端:"+s);
try{
new ServerOneThread(s);
}catch(IOException e){
s.close();
}
}
} catch (Exception e) {
System.out.println("11111111"+e);
} finally{
serverSocket.close();
System.out.println("finally6666");
}
}
}
客户端代码
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Scanner;
import org.omg.CORBA.Current;
public class JavaClientSocket {
public static void main(String[] args) {
try {
InetAddress addr = InetAddress.getByName("ZXW-20160708ZJG");
System.out.println("addr = " + addr);
Socket socket = new Socket(addr, 8080);
try {
BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
PrintWriter out = new PrintWriter(
new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream())),true);
// new ReceiveDataThread(in);
new ChatOption().selectSort(in);
while(true){
System.out.print("请输入数据:");
Scanner userInput = new Scanner(System.in);
String inputData = userInput.next();
out.println(inputData);
}
} catch (IOException e) {
e.printStackTrace();
} finally{
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
class ReceiveDataThread extends Thread{
BufferedReader in;
public ReceiveDataThread(BufferedReader in) {
this.in = in;
start();
}
@Override
public void run() {
super.run();
try {
while(true){
System.out.println(in.readLine());
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
class ChatOption{
public void selectSort(BufferedReader in){
Scanner userInput = new Scanner(System.in);
boolean flag = false;
while(!flag){
System.out.println("选择聊天类型:\n0:群聊\n1:私聊\n2:ThreadTest");
int inputData = -1;
try{
inputData = userInput.nextInt();
}catch(Exception e){
System.out.println("请输入0/1/2!");
}
switch (inputData) {
case 0:
flag = true;
break;
case 1:
System.out.println("选择在线用户:......");
System.out.println("目前不支持私聊(づ ̄ 3 ̄)づ");
break;
case 2:
for(int i = 0;i<30;i++){
new Thread(new Runnable() {
private Socket socket;
@Override
public void run() {
try{
InetAddress addr = InetAddress.getByName("ZXW-20160708ZJG");
System.out.println("addr = " + addr);
socket = new Socket(addr, 8080);
System.out.println("Socket:"+socket);
PrintWriter out = new PrintWriter(
new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream())),true);
for(int i = 0;i<20;i++){
out.println("客户线程:"+Thread.currentThread().getName() +"第"+i+"次执行");
}
}catch(Exception e){
System.out.println(e);
}finally{
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}).start();;
}
flag = true;
break;
default:
break;
}
}
if(flag){
new ReceiveDataThread(in);
}
}
}
问题
当客户端开启很多线程不停的发送消息时,服务器端在查询已连接的客户端时,会报错:
Exception in thread "Thread-162" java.util.ConcurrentModificationException
这应该是多线程同时访问同一个资源时产生竞争,但是当把共享资源加锁后还是会报错,只是出现的几率少了,并且如果给socketMap加锁,会使程序运行时间大大增加,
给map加锁后其他的线程应该不能用map生成迭代器去hasNext
原因是在socket连接中发生异常,使synchronized把锁释放了。