CodeGym /Blogue Java /Random-PT /Melhor juntos: Java e a classe Thread. Parte I — Threads ...
John Squirrels
Nível 41
San Francisco

Melhor juntos: Java e a classe Thread. Parte I — Threads de execução

Publicado no grupo Random-PT

Introdução

O multithreading foi incorporado ao Java desde o início. Então, vamos dar uma breve olhada nessa coisa chamada multithreading. Melhor juntos: Java e a classe Thread.  Parte I — Threads de execução - 1Tomamos como ponto de referência a lição oficial da Oracle: " Lesson: The "Hello World!" Application ". Vamos alterar um pouco o código do nosso programa Hello World da seguinte forma:

class HelloWorldApp {
    public static void main(String[] args) {
        System.out.println("Hello, " + args[0]);
    }
}
argsé uma matriz de parâmetros de entrada passados ​​quando o programa é iniciado. Salve este código em um arquivo com um nome que corresponda ao nome da classe e tenha a extensão .java. Compile-o usando o utilitário javacjavac HelloWorldApp.java : . Então, rodamos nosso código com algum parâmetro, por exemplo, "Roger": java HelloWorldApp Roger Melhor juntos: Java e a classe Thread.  Parte I — Threads de execução - 2Nosso código atualmente está com uma falha grave. Se você não passar nenhum argumento (ou seja, executar apenas "java HelloWorldApp"), obteremos um erro:

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0
        at HelloWorldApp.main(HelloWorldApp.java:3)
Ocorreu uma exceção (ou seja, um erro) no thread denominado "principal". Então, Java tem threads? É aqui que nossa jornada começa.

Java e tópicos

Para entender o que é um thread, você precisa entender como um programa Java é iniciado. Vamos alterar nosso código da seguinte forma:

class HelloWorldApp {
    public static void main(String[] args) {
		while (true) { 
			// Do nothing
		}
	}
}
Agora vamos compilá-lo novamente com javac. Por conveniência, executaremos nosso código Java em uma janela separada. No Windows, isso pode ser feito assim: start java HelloWorldApp. Agora usaremos o utilitário jps para ver quais informações o Java pode nos fornecer: Melhor juntos: Java e a classe Thread.  Parte I — Threads de execução - 3O primeiro número é o PID ou ID do processo. O que é um processo?

A process is a combination of code and data sharing a common virtual address space.
Com os processos, diferentes programas são isolados uns dos outros enquanto são executados: cada aplicativo usa sua própria área na memória sem interferir em outros programas. Para saber mais, recomendo a leitura deste tutorial: Processos e Threads . Um processo não pode existir sem um thread, portanto, se um processo existir, ele terá pelo menos um thread. Mas como isso acontece em Java? Quando iniciamos um programa Java, a execução começa com o mainmétodo. É como se estivéssemos entrando no programa, então esse mainmétodo especial é chamado de ponto de entrada. O mainmétodo deve ser sempre "public static void", para que a máquina virtual Java (JVM) possa começar a executar nosso programa. Para obter mais informações, Por que o método principal Java é estático?. Acontece que o iniciador Java (java.exe ou javaw.exe) é um aplicativo C simples: ele carrega as várias DLLs que realmente compõem a JVM. O ativador Java faz um conjunto específico de chamadas Java Native Interface (JNI). JNI é um mecanismo para conectar o mundo da máquina virtual Java com o mundo do C++. Portanto, o iniciador não é a própria JVM, mas sim um mecanismo para carregá-la. Ele conhece os comandos corretos a serem executados para iniciar a JVM. Ele sabe como usar chamadas JNI para configurar o ambiente necessário. A configuração desse ambiente inclui a criação do thread principal, que é chamado de "principal", é claro. Para ilustrar melhor quais threads existem em um processo Java, usamos o jvisualvmferramenta, que está incluída no JDK. Conhecendo o pid de um processo, podemos ver imediatamente informações sobre esse processo: jvisualvm --openpid <process id> Melhor juntos: Java e a classe Thread.  Parte I — Threads de execução - 4Curiosamente, cada thread tem sua própria área separada na memória alocada para o processo. Essa estrutura de memória é chamada de pilha. Uma pilha consiste em quadros. Um quadro representa a ativação de um método (uma chamada de método inacabada). Um quadro também pode ser representado como um StackTraceElement (consulte a API Java para StackTraceElement ). Você pode encontrar mais informações sobre a memória alocada para cada thread na discussão aqui: " Como Java (JVM) aloca pilha para cada thread ". Se você observar a API Java e pesquisar a palavra "Thread", encontrará o java.lang.Threadaula. Esta é a classe que representa um thread em Java e precisaremos trabalhar com ela. Melhor juntos: Java e a classe Thread.  Parte I — Threads de execução - 5

java.lang.Thread

Em Java, um thread é representado por uma instância da java.lang.Threadclasse. Você deve entender imediatamente que as instâncias da classe Thread não são threads de execução. Este é apenas um tipo de API para os encadeamentos de baixo nível gerenciados pela JVM e pelo sistema operacional. Quando iniciamos a JVM usando o iniciador Java, ela cria um mainencadeamento chamado "principal" e alguns outros encadeamentos de manutenção. Conforme declarado no JavaDoc para a classe Thread: When a Java Virtual Machine starts up, there is usually a single non-daemon thread. Existem 2 tipos de threads: daemons e não-daemons. Os encadeamentos daemon são encadeamentos de segundo plano (manutenção) que realizam algum trabalho em segundo plano. A palavra "daemon" refere-se ao demônio de Maxwell. Você pode aprender mais neste artigo da Wikipédia . Conforme declarado na documentação, a JVM continua executando o programa (processo) até:
  • O método Runtime.exit() é chamado
  • Todos os threads NÃO-daemon terminam seu trabalho (sem erros ou com exceções lançadas)
Um detalhe importante decorre disso: os encadeamentos do daemon podem ser encerrados a qualquer momento. Como resultado, não há garantias sobre a integridade de seus dados. Conseqüentemente, os encadeamentos daemon são adequados para certas tarefas de manutenção. Por exemplo, Java possui uma thread que é responsável por processar finalize()chamadas de métodos, ou seja, threads envolvidas com o Garbage Collector (gc). Cada thread faz parte de um grupo ( ThreadGroup ). E os grupos podem fazer parte de outros grupos, formando uma certa hierarquia ou estrutura.

public static void main(String[] args) {
	Thread currentThread = Thread.currentThread();
	ThreadGroup threadGroup = currentThread.getThreadGroup();
	System.out.println("Thread: " + currentThread.getName());
	System.out.println("Thread Group: " + threadGroup.getName());
	System.out.println("Parent Group: " + threadGroup.getParent().getName());
}
Os grupos trazem ordem ao gerenciamento de encadeamentos. Além dos grupos, os threads têm seu próprio manipulador de exceções. Dê uma olhada em um exemplo:

public static void main(String[] args) {
	Thread th = Thread.currentThread();
	th.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
		@Override
		public void uncaughtException(Thread t, Throwable e) {
			System.out.println("An error occurred: " + e.getMessage());
		}
	});
    System.out.println(2/0);
}
A divisão por zero causará um erro que será detectado pelo manipulador. Se você não especificar seu próprio manipulador, a JVM invocará o manipulador padrão, que produzirá o rastreamento de pilha da exceção para StdError. Cada thread também tem uma prioridade. Você pode ler mais sobre prioridades neste artigo: Java Thread Priority in Multithreading .

Criando um tópico

Conforme declarado na documentação, temos 2 maneiras de criar um thread. A primeira maneira é criar sua própria subclasse. Por exemplo:

public class HelloWorld{
    public static class MyThread extends Thread {
        @Override
        public void run() {
            System.out.println("Hello, World!");  
        }
    }
    
    public static void main(String[] args) {
        Thread thread = new MyThread();
        thread.start();
    }
}
Como você pode ver, o trabalho da tarefa acontece no run()método, mas o próprio thread é iniciado no start()método. Não confunda esses métodos: se chamarmos o un()método r diretamente, nenhum novo thread será iniciado. É o start()método que solicita à JVM a criação de um novo thread. Esta opção onde herdamos Thread já é ruim porque incluímos Thread em nossa hierarquia de classes. A segunda desvantagem é que estamos começando a violar o princípio da "responsabilidade única". Ou seja, nossa classe é simultaneamente responsável por controlar a thread e por alguma tarefa a ser executada nesta thread. Qual é o caminho certo? A resposta é encontrada no mesmo run()método, que sobrescrevemos:

public void run() {
	if (target != null) {
		target.run();
	}
}
Aqui targetestá algum java.lang.Runnable, que podemos passar ao criar uma instância da classe Thread. Isso significa que podemos fazer isso:

public class HelloWorld{
    public static void main(String[] args) {
        Runnable task = new Runnable() {
            public void run() {
                System.out.println("Hello, World!");
            } 
        };
        Thread thread = new Thread(task);
        thread.start();
    }
}
Runnabletambém tem sido uma interface funcional desde o Java 1.8. Isso torna possível escrever um código ainda mais bonito para a tarefa de um thread:

public static void main(String[] args) {
	Runnable task = () -> { 
		System.out.println("Hello, World!");
	};
	Thread thread = new Thread(task);
	thread.start();
}

Conclusão

Espero que esta discussão esclareça o que é um thread, como os threads surgem e quais operações básicas podem ser executadas com threads. Na próxima parte , tentaremos entender como os threads interagem uns com os outros e exploraremos o ciclo de vida do thread. Melhor juntos: Java e a classe Thread. Parte II — Sincronização melhor juntos: Java e a classe Thread. Parte III — Interação melhor juntos: Java e a classe Thread. Parte IV — Callable, Future e amigos Melhor juntos: Java e a classe Thread. Parte V — Executor, ThreadPool, Fork/Join Better juntos: Java e a classe Thread. Parte VI — Atire!
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION