Uma duvida sobre threads

Bem, a minha dúvida é uma curiosidade para eu poder entender melhor sobre threads.
Por exemplo:

Nesse código eu chamo um frame que vai exibir uma imagem e que vai girar de acordo com o mover do mouse.

public final class Testes{
    public static void main(String[] args){
        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    new JanelaImagens().setVisible(true);
                } catch (IOException ex) {
                    Logger.getLogger(Testes.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        });
    }
}

Agora que vem a questão: por que não posso escrever dessa forma já que tbm funciona?

public final class Testes{
    public static void main(String[] args) throws IOException{
         new JanelaImagens().setVisible(true);
    }
}

Qual a diferença? e tbm queria saber a diferença de thread safe pra outras thread

Você pode.
O que ocorre é que isso fará com que você esteja “anexando” a execução dessa janela à mesma thread que já está em execução.
Como é apenas essa janela, não há qualquer problema.
Agora, se você estivesse abrindo de dentro de outra aplicação, a partir do clique de um botão, por exemplo, não seria interessante manter essa outra aplicação indisponível, não acha?
É só por isso que se sugere que se use threads, para que cada coisa fique em sua própria thread isolada.

Então se eu atribuir outras ações nessa mesma thread, ela só vão ocorrer depois de executar a janela?

Se as ações forem dispostas após a instanciação da nova janela, sim.
O comportamento será o mesmo de quando você tem um método qualquer, tudo é executado linearmente, enquanto uma linha não é finalizada, a outra não inicia.

Então em qualquer aplicação, o ideal seja que cada classe tenha a sua thread? ou isso dificilmente é nescessário? por exemplo um jogo ou isso acontece mais com frequencia quando se trata de códigos para aplicações diferentes de jogos?

Não.
Tudo precisa ser usado com parcimônia.
Thread não é como log que você vai sair usando à torta e à direita.
Precisa ser coerente.
em mais de 8 anos de desenvolvimento, poucas foram as vezes em que usei threads (mesmo desenvolvendo para web e em ambientes que precisavam de muita performance).
Sobre jogos eu não sei muito, afinal, não é meu nicho de trabalho.

2 curtidas

Vamos por partes.

Para a maioria das aplicações (jogos inclusive), uma única thread é suficiente. O código precisa ser estruturado de forma que tudo ocorra dentro dessa thread. No caso do Swing, como comentei no seu outro tópico, existe uma thread especial em que sua aplicação é chamada. Isso permite que o Swing receba informações e interaja com seus componentes através de uma única linha de processamento (essa thread). Processamentos pesados que precisem rodar em paralelo à janela da aplicação podem enviar mensagens para a janela, mas isso é geralmente feito através de classes especiais, como SwingWorker, que já são estruturadas de modo a garantir um canal de comunicação entre as threads, mas mesmo isso é sujeito à erros.

Resumidamente, o problema do “thread-safe” do Swing é o seguinte:

  • imagine que você tem um JFrame chamado janela, com um JLabel chamado jogador e outro chamado inimigo;
  • paralelamente, existe uma thread que move o jogador, verificando se as setas estão pressionadas. Essa thread contém uma referência (atributo) para o JLabel jogador, para poder interagir com ele;
  • e uma thread move o inimigo. Também tem uma referência (atributo) ao JLabel inimigo;
  • como o inimigo se move sozinho, quando ele colide com o jogador, o jogador morre e o JLabel jogador é excluído (jogador = null);
  • mas a thread que move o jogador ainda têm uma referência, e tentará atualizá-la com setLocation. Porém a referência está nula dentro do Swing, e você obtém um nullpointerexception.

Você pode estar pensando que poderia tentar sincronizar as threads (inclusive a do Swing) ou que, antes da movimento, pode verificar se o objeto está nulo, ou mesmo colocar os métodos dentro do Swing que façam as operações, e esses métodos sejam chamados pelas threads. Mas note que você está aumentando a complexidade para adequar a aplicação à presença de várias threads simultâneas, com pouco ou nenhum ganho.

Mas fica um pouco pior: eventos dentro da thread do Swing não são executados imediatamente, são “enfileirados para execução”. Ou seja, quando a thread que move o jogador executa, ela ainda tem uma referência válida ao JLabel jogador, mas quando o setLocation que essa thread chama é executado, essa referência pode ser nula. Nullpointerexception de novo.

O ponto importante é: você não usará threads auxiliares para interagir com os componentes do Swing (que já estão rodando dentro de uma thread). Idealmente, você fará essas operações dentro da thread do Swing, em que há mais garantias de que as coisas sejam executadas da forma como deveriam, e mesmo assim, para o caso de jogos, o fato de a execução precisar respeitar determinados intervalos de tempo (FPS), dificulta as coisas, pois dentro do Swing você não tem garantia dessas coisas.

Se você realmente quer usar Java para fazer um jogo não estático (como um card game seria), recomendo:

Obviamente, se você faz questão de usar o Swing e threads para tal, esteja preparado para problemas como esse.

Abraço.

1 curtida

Eu não entendi essa parte muito bem:

E nessa parte pra eu entende se quer dizer que pra caso eu queira por exemplo um jogo mais dinamico, isso se torna mais complicado de fazer devido ao enfileiramento:

E só mais uma pergunta, uma engine que vc fala, seria extamente oq? tipo um gamemaker? se for, eu até gostaria de fazer mas tipo, eu gosto de entender bem como funciona os mecanismos então, prefiro fazer no braço e aprender bem a fundo sobre o assunto, poder analisar os problemas que ocorrem, entender o porquer e por ai vai, mas também não é que eu não esteja disposto a mecher com isso mas é que eu to querendo me dedicar bem a aprender a linguagem Java, além de que eu to aprendendo e tendo experiencias com HTML, css e um pouco de JavaScript de pouco a pouco com o tempo, eu ainda não conseguir estudar firmamente sobre Android, pq eu uso o Android Studio e ele pesa muito, ou seja meu pc ta lagando bem com ele, mas tem dia que eu consigo prossergui um pouco pelo menos.

É um pouco complicado de explicar mesmo (tem um artigo que explica esse problema, de usar threads em combinação com toolkits visuais como o Swing, mas não achei aqui). Mas, basicamente, o Swing não garante que um objeto referenciado por outra thread (que não a do Swing) poderá ser acessado diretamente. Isso pode causar nullpointerexception, dentre outros problemas. Por isso que a documentação do Swing diz que ele não é thread-safe.

Pense num JLabel com uma imagem (como no seu outro tópico).

Você chama o método setLocation pra mudar a posição desse JLabel.

Você imagina que ele será executado imediatamente, mas o Swing não dá essa garantia.

Ele pode decidir que só vai executar o setLocation daqui a 100 milissegundos.

Ou seja, somente daqui a um décimo de segundo é que o Swing tentará reposicionar seu JLabel.

Mas, entre o momento atual e o momento em que o setLocation é efetivamente executado, uma outra thread vem e deleta o JLabel (seta a variável pra null). Quando você chamou o setLocation, o JLabel existia, mas quando chegou o momento do Swing executar o setLocation, o objeto não existe mais. NullpointerException (ou qualquer coisa parecida) ocorrerá.

Esse não é um problema único do Swing. Sincronia de threads e toolkits de UI é um caso problemático.

Sim, mais ou menos isso. Dê uma olhada na libGDX.

Meu ponto é: se você quer estudar Java (e threads fazem parte disso), não tem problema algum. Mas sua tentativa de fazer um jogo (algo que já é normalmente complexo) e ainda controlá-lo através de threads vai te dar muito mais trabalho do que pode parecer, e o tempo que você gastaria com isso pode ser melhor aproveitado em outros tópicos.

Mas é minha opinião apenas.

Como extra, dê uma olhada nesse Mario feito em Java, pelo David Buzzato, pra entender como poderia funcionar um jogo em Java.

Abraço.