Chat em java usando Socket e Thread

[quote=ViniGodoy]Esse código eu montei em aula, com os alunos. Primeiro desenhamos um protocolo, e eu fui explicando os desafios de enviar e receber dados. Por que você precisa de tamanhos, como o socket funciona, como funcionam os reads e os writes. Depois programamos isso na frente da turma. E depois passei de lição para que eles adicionassem troca de arquivos no protocolo.

Foi muito interessante, a turma gostou muito. Geralmente eles gostam de ver professores “colocando a mão na massa”.[/quote]

modifiquei seu código fazendo ele comunicar com outro cliente ao invés de cliente servidor , se quiser verificar o código posso postar aqui , para poder indicar os pontos fracos do meu código.

Preciso de ajuda para fazer retornar as mensagens agora aos clientes. Dei uma repaginada em todo o fonte para funcionar melhor.
São tres classes responsáveis por isso listadas abaixo.

ChatServer

import java.io.IOException;
import java.net.ServerSocket;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class ChatServer implements Runnable {
	
	private static final int PORTA = 45054;
	private static List<Usuario> lista = new ArrayList<Usuario>();
	private Usuario cliente;

	public ChatServer(Usuario cliente) {
		this.cliente = cliente;
	}

	@Override
	public void run() {
		try {
			DateFormat dateFormat = DateFormat.getDateTimeInstance();
			System.out.println("["+dateFormat.format(new Date())+"] Atendendo Cliente ("+cliente.getIp()+").");
			String msg;
			do{
				cliente.setNome(cliente.getEntrada().readLine());
				msg = cliente.getEntrada().readLine();
				//entrada.close();
				if(!msg.equals("Sair")){
					System.out.println(cliente.getNome()+" disse: "+msg);
					if(!msg.isEmpty()){
						for (Usuario usuarioLogado : lista) {
							usuarioLogado.getSaida().write(msg);
							usuarioLogado.getSaida().newLine();
							usuarioLogado.getSaida().flush();
						}
					}
				}else{
					System.out.println("["+dateFormat.format(new Date())+"] Cliente ("+cliente.getIp()+") desconectado.");
					cliente.disconnect();
					atualizaLista();
				}
			}while(!msg.equals("Sair"));
		} catch (IOException e) {
			System.err.println("Erro: "+e.getMessage());
			System.exit(-1);
		}
	}

	private void atualizaLista() {
		for (int i=0; i<lista.size(); i++) {
			if(lista.get(i).getConexao().isClosed()){
				lista.remove(i);
				i--;
			}
		}
	}

	public static void main(String[] args) {
		try {
			DateFormat dateFormat = DateFormat.getDateTimeInstance();
			System.out.println("["+dateFormat.format(new Date())+"] Inicializando Servidor de chat.");
			ServerSocket servidor = new ServerSocket(PORTA);
			System.out.println("["+dateFormat.format(new Date())+"] Servidor de chat executando na porta "+PORTA+".");
			System.out.println("["+dateFormat.format(new Date())+"] Aguardando conexões de Clientes.");
			while(true){
				Usuario cliente = new Usuario(servidor.accept());
				System.out.println("["+dateFormat.format(new Date())+"] Conexão aceita de Cliente ("+cliente.getIp()+").");
				lista.add(cliente);
				new ChatServer(cliente).run();
			}
		} catch (IOException e) {
			System.err.println("Erro: "+e.getMessage());
			System.exit(-1);
		}
		
	}
}

ChatClient

import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.text.DateFormat;
import java.util.Date;
import java.util.Scanner;

public class ChatClient implements Runnable {
	
	private static final int PORTA = 45054;
	private Usuario cliente;

	public ChatClient(Usuario cliente2) {
		this.cliente = cliente2;
	}

	@Override
	public void run() {
		try {
			String msg;
			do{
				msg = cliente.getEntrada().readLine();
				if(!msg.equals("Sair")){
					System.out.println(cliente.getNome()+" disse: "+msg);
				}
			}while(!msg.equals("Sair"));
			cliente.disconnect();
		} catch (IOException e) {
				System.err.println("Erro: "+e.getMessage());
				System.exit(-1);
		}
	}

	public static void main(String[] args) {
		if(args.length==0 || args[0].length()==0 || args[1].length()==0){
			System.out.println("Uso incorreto. Tente:\n\t" +
					"java ChatCliente ><ip ou hostname> <nome de usuario>");
			System.exit(-1);
		}
		try {
			Scanner scan = new Scanner(System.in);
			DateFormat dateFormat = DateFormat.getDateTimeInstance();
			System.out.println("<"+dateFormat.format(new Date())+"> Conectando ao Servidor de chat.");
			Usuario cliente = new Usuario(new Socket(args[0], PORTA));
			cliente.setNome(args[1]);
			System.out.println("<"+dateFormat.format(new Date())+"> Iniciando serviço de mensagens.");
			//new ChatClient(cliente).run();
			System.out.println("<"+dateFormat.format(new Date())+"> Pronto para envio e recebimento de mensagens.");
			System.out.println("Digite uma mensagem e pressione enter para enviá-la ou digite 'Sair' para desconectar.");
			String msg;
			do{
				msg = scan.nextLine();
				cliente.getSaida().write(cliente.getNome());
				cliente.getSaida().newLine();
				cliente.getSaida().write(msg);
				cliente.getSaida().newLine();
				cliente.getSaida().flush();
			}while (!msg.equals("Sair"));
			System.out.println("<"+dateFormat.format(new Date())+"> Cliente se desconectou do Servidor de chat.");
			cliente.disconnect();
		} catch (UnknownHostException e) {
			System.err.println("Erro: "+e.getMessage());
			System.exit(-1);
		} catch (IOException e) {
			System.err.println("Erro: "+e.getMessage());
			System.exit(-1);
		}
	}

}

Usuario

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;

public class Usuario {
	private String nome;
	private Socket conexao;
	private BufferedReader entrada;
	private BufferedWriter saida;
	
	public Usuario(Socket conexao) throws IOException {
		super();
		this.conexao = conexao;
		this.entrada = new BufferedReader(new InputStreamReader(conexao.getInputStream()));
		this.saida = new BufferedWriter(new OutputStreamWriter(conexao.getOutputStream()));
	}

	public String getNome() {
		return nome;
	}

	public void setNome(String nome) {
		this.nome = nome;
	}

	public Socket getConexao() {
		return conexao;
	}
	
	public String getIp(){
		return conexao.getLocalAddress().getHostAddress();
	}

	public void setConexao(Socket conexao) {
		this.conexao = conexao;
	}

	public BufferedReader getEntrada() {
		return entrada;
	}

	public void setEntrada(BufferedReader entrada) {
		this.entrada = entrada;
	}

	public BufferedWriter getSaida() {
		return saida;
	}

	public void setSaida(BufferedWriter saida) {
		this.saida = saida;
	}

	@Override
	public String toString() {
		return nome;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((conexao == null) ? 0 : conexao.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Usuario other = (Usuario) obj;
		if (conexao == null) {
			if (other.conexao != null)
				return false;
		} else if (!this.getIp().equals(other.conexao.getLocalAddress().getHostAddress()))
			return false;
		return true;
	}

	public void disconnect() throws IOException {
		entrada.close();
		saida.close();
		conexao.close();
	}

	
}

Preciso de uma ajuda com isso galera. Estou fazendo especialização em Java e tenho problema quando descomento a linha 47 do ChatClient a aplicação trava e não permite o envio de mensagens.