Threads em Java

Opa Galera sou iniciante em Java e estou precisando criar uma Thread que fique executando enquanto um cliente estiver conectado via socket.

Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+" Start.");
                System.out.println(Thread.currentThread().getName()+" End.");
            }
        }, delay, intervalo em milissegundos);

Você quer que cada conexão seja tratada em uma thread separada?

import java.net.Socket;
import java.net.ServerSocket;
import java.io.IOException;

class Main {
    public static void main(String[] args) {
        int porta = leEntrada(args);
        try {
            ServerSocket server = new ServerSocket(porta);
            while (true) {
                Socket client = server.accept();
                new Thread(codigoExecutadoPelaThread(client)).start();
            }
        } catch (IOException ex) {
            System.err.println("Ocorreu um erro na thread principal do servidor.");
            ex.printStackTrace();
        }
    }

    public static int leEntrada(String[] args) {
        int porta = -1;
        try {
            porta = Integer.parseInt(args[0]);
        } catch (NumberFormatException | ArrayIndexOutOfBoundsException ex) {
            System.err.println("Chamda inválida. Uso: java Main <porta>");
            System.exit(1);
        }
        return porta;
    }

    public static Runnable codigoExecutadoPelaThread(Socket client) {
        return () -> {
            // aqui você coloca o código que vai ser executado numa nova thread,
            // que utiliza o client.
            // Eu acho melhor você criar uma classe que implementa a interface Runnable,
            // mas isso aqui vai servir.
            try {
                client.close();
            } catch (IOException ex) {
                System.err.println("Erro ao tentar fechar o socket.");
                ex.printStackTrace();
            }
        };
    }

}

Assim. Quero fazer uma Thread com socketServer que fique esperando conexões de cliente. Cada cliente terá um socketServer e uma porta. Quando um cliente desconectar ele enviara para essa Thread uma String “Fim” antes de desconectar. Ao se desconectar a Thread deverá novamente aguardar conexões deste mesmo cliente. Pra ser mais exato serão 4 clientes.

Desculpem a gambiarra mas estou aprendendo:

private void iniciarServidor()
{
try {
serverSocket5 = new ServerSocket (2345);
serverSocket6 = new ServerSocket (2346);
serverSocket7 = new ServerSocket (2347);
serverSocket8 = new ServerSocket (2348);
jLabelServidor.setText(“Servidor Online”);
} catch (IOException ex) {
Logger.getLogger(Menu_Jf.class.getName()).log(Level.SEVERE, null, ex);
}

    new Thread()
    {
    public void run()
    {
   
    try
        {    
        while(true)
        {
            Socket socket5 = serverSocket5.accept();
        if (socket5.isBound()== true)
        {
          JOptionPane.showMessageDialog(null,"Leitor 5. Conexão Iniciada com IP:  \n"+socket5.getInetAddress().toString()+"Porta: "+socket5.getPort());
          Recebido = new DataInputStream(socket5.getInputStream());
          if(Recebido.readUTF().equals("FIM"))
          {
          //JOptionPane.showMessageDialog(null,"Leitor 5 desconectou");
          Recebido = null;
          }
          }

/////Aqui gostaria que a Thread voltasse a esperar conexão do mesmo cliente que desconectou como um loop que fica atualizando se o cliente esta conectado.

}.start(); ///

Como sou iniciante em java e ainda mais em Thread não entendi exatamente como funciona uma Thread para ela ficar executando em segundo plano junto ao main. Desde já agradeço a ajuda

Vou assumir que você entendeu como funcionam threads no sistema operacional. Quando você cria um objeto do tipo Thread, esse objeto representa uma thread física do sistema. Ao chamar o método start, você inicializa a execução em paralelo dessa thread criada.

Thread t = new Thread(runnable);
// essa chamada ao método start() retorna imediatamente,
// e a thread que estamos agora continua
// executando normalmente.
t.start();
outraOperacao();
outraOperacao();
//...

Quando chamamos o start(), a nova thread começa sua execução, de forma independente à thread que a criou, um fluxo de execução completamente diferente. É como se fossem dois programas rodando agora.

O seu raciocínio é o seguinte, pelo que eu entendi: você quer uma thread dedicada para cada cliente, correto? Eu faria de uma maneira um pouquinho diferente, como mandei no exemplo para você ali antes.

  1. A thread principal abre o servidor e espera conexões infinitamente
  2. Quando chega uma nova conexão (ou seja, quando o método accept() retorna), uma nova thread é criada para se comunicar com o cliente
  3. No código da thread, eu faria com que o cliente se identificasse (com um número ou uma string, por exemplo), e a partir daí saberia o que fazer.

Porém, vou tentar te dar algumas ideias do que fazer para continuar com a tua linha de raciocínio.

Você pode fazer o seguinte:

  1. Continuar o que fez, associando de forma fixa uma porta para cada cliente;
  2. Cria uma classe que herda de Thread, e implementa o método run. Para o objeto dessa nova classe, você vai passar qualquer tipo de informação de contexto necessária para que ele identifique o cliente.
  3. O método run vai ficar escutando na porta determinada para o cliente, e quando chegar uma conexão, vai saber o que fazer (baseado nos parâmetros passados)

Vou tentar exemplificar isso da forma mais sucinta possível, para que tu entenda e generalize para o teu caso específico, ok?

Vamos lá:

import java.net.Socket;
import java.net.ServerSocket;
import java.io.IOException;

class Main {

    public static void main(String[] args) {
        ThreadCustomizada t1 = new ThreadCustomizada(2345, "Cliente 1");
        ThreadCustomizada t2 = new ThreadCustomizada(2346, "Cliente 2");
        ThreadCustomizada t3 = new ThreadCustomizada(2347, "Cliente 3");
        ThreadCustomizada t4 = new ThreadCustomizada(2348, "Cliente 4");
        // até aqui tem apenas 1 thread rodando (na verdade tem outras, o Garbage Collector por exemplo, mas enfim)
        t1.start(); // a partir daqui existem 2 threads rodando
        t2.start(); // 3 agora
        t3.start(); // 4
        t4.start(); // 5 threads rodando

        // aqui a thread principal morre quando acaba o método main,
        // mas as outras 4 estão executando, por isso o programa continua até que todas morram
    }
}

class ThreadCustomizada extends Thread {
    private final int porta;
    private final String nomeDoCliente;
    /*
        pode passar o que quiser pro construtor,
        tudo o que for necessário para lidar com o cliente
    */
    ThreadCustomizada(int porta, String nomeDoCliente) {
        this.porta = porta;
        this.nomeDoCliente = nomeDoCliente;
    }
    @Override
    public void run() {
        try {
            ServerSocket server = new ServerSocket(this.porta);

            // Fica esperando o cliente se conectar sempre
            while (true) {
                // essa chamada bloqueia (fica travada, não sai do lugar)
                // até que o cliente se conecte. Quando isso acontecer,
                // o método accept retorna e a execução continua.
                Socket client = server.accept();
                // aqui você faz tudo o que quiser com o socket
                // no momento que o cliente sair, o while reinicia
                // e fica esperando por aquele cliente específico novamente,
                // na mesma porta
                client.close();
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
}

Obrigadão pela ajuda, era isso mesmo que eu queria fazer. Só agora estou com um problema quanto as portas de cada socket. Pois quando o cliente 2 se conecta e o 1 está desconectado ele não respeita o número da porta setado e utiliza o socket do Cliente 1. Desde já muito obrigado pela ajuda.