Java Multithreading (um)
Como um ponto de conhecimento muito importante em Java, ainda é necessário resumir aqui.
1. O ciclo de vida de um tópico e os cinco estados básicos
Em relação ao ciclo de vida dos threads em Java, vamos primeiro olhar para a imagem clássica a seguir:
A figura acima abrange basicamente os importantes pontos de conhecimento da multi-threading em Java. Depois de dominar os pontos de conhecimento na figura acima, você basicamente domina a multi-threading em Java. Incluindo principalmente:
Os threads java têm cinco estados básicos
Novo estado (novo): Quando um par de objetos de thread é criado, ele entra em um novo estado, como: thread t = new mythread ();
Estado pronto (Runnable): Quando o método start () do objeto Thread (t.start ();), o encadeamento entra no estado pronto. Um segmento no estado pronto significa apenas que o thread está pronto e está esperando a CPU agendar a execução a qualquer momento, não que o thread seja executado imediatamente após a execução de t.start ();
Estado em execução: quando a CPU começa a agendar threads no estado pronto, o thread pode ser realmente executado, ou seja, entra no estado em execução. Nota: O estado pronto é a única entrada para o estado em execução, ou seja, se um thread deseja entrar no estado em execução para executar, ele deve estar primeiro no estado pronto;
Estado bloqueado: por algum motivo, um encadeamento no estado em execução desiste temporariamente do uso da CPU e interrompe a execução. Neste momento, entra no estado de bloqueio. Não terá a chance de ser chamado pela CPU novamente para entrar no estado em execução. De acordo com os motivos do bloqueio, os estados de bloqueio podem ser divididos em três tipos:
1. Aguardando o bloqueio: o thread no estado em execução executa o método wait () para fazer com que o thread entre no estado de bloqueio;
2. Bloqueio sincronizado- o encadeamento falha em adquirir a trava de sincronização sincronizada (porque a trava é ocupada por outros threads), ele entrará no estado de bloqueio sincronizado;
3. Outro bloqueio-o thread entrará em um estado de bloqueio chamando Sleep () ou ingressar () do thread ou emitindo uma solicitação de E/S. Quando o Sleep () State se estendeu, a junção () esperou que o thread termine ou o tempo de tempo ou o processamento de E/S tenha sido concluído, o thread reinseriu para o estado pronto.
Morto: o thread terminou de executar ou sair do método run () devido a uma exceção, e o thread termina seu ciclo de vida.
2. Criação e startup de Java Multithreads
Existem três formas básicas de criação de threads em java
1. Herde a classe de encadeamento e substitua o método run () da classe.
classe mythread estende o thread {private int i = 0; @Override public void run () {for (i = 0; i <100; i ++) {System.out.println (thread.currentThread (). GetName () + "" + i); }}} public class ThreadTest {public static void main (string [] args) {for (int i = 0; i <100; i ++) {System.out.println (thread.currentThread (). getName () + "" + i); if (i == 30) {thread mythread1 = new mythread (); // Crie um novo thread mythread1 Este thread entra no novo thread de estado mythread2 = new mythread (); // Crie um novo thread mythread2 Este thread entra no novo estado mythread1.start (); // Ligue para o método START () para fazer com que o thread entre no estado pronto mythread2.start (); // Ligue para o método START () para fazer o thread entrar no estado pronto}}}}Como mostrado acima, herdando a classe Thread, um novo mythread da classe de thread é definido pela substituição do método run (), onde o corpo do método do método run () representa a tarefa que o thread precisa concluir e é chamado de corpo de execução do thread. Ao criar este objeto de classe de thread, um novo thread é criado e entra no novo estado do thread. Ao chamar o método start () referenciado pelo objeto Thread, o encadeamento entra no estado pronto. No momento, o thread não pode ser executado imediatamente, dependendo do tempo de agendamento da CPU.
2. Implemente a interface executável e substitua o método run () da interface. O método run () também é um corpo de execução de thread, crie uma instância da classe de implementação executável e use essa instância como o destino da classe Thread para criar um objeto Thread. O objeto Thread é o objeto de encadeamento real.
classe MyRunnable implementa runnable {private int i = 0; @Override public void run () {for (i = 0; i <100; i ++) {System.out.println (thread.currentThread (). GetName () + "" + i); }}} public class ThreadTest {public static void main (string [] args) {for (int i = 0; i <100; i ++) {System.out.println (thread.currentThread (). getName () + "" + i); if (i == 30) {runnable myRunnable = new MyRunnable (); // Crie um objeto da classe de implementação executável thread1 = novo thread (myRunnable); // Crie um novo thread com MyRunnable como um thread Thread Thread2 = novo thread (MyRunnable); Thread1.start (); // Ligue para o método START () para fazer com que o thread entre no thread.start.start (); }}}} Eu acredito que todos estão familiarizados com as duas maneiras acima de criar novos tópicos. Então, qual é a relação entre Thread e Runnable? Vamos primeiro olhar para o exemplo a seguir.
public class ThreadTest {public static void main (string [] args) {for (int i = 0; i <100; i ++) {System.out.println (thread.currentThread (). getName () + "" + i); if (i == 30) {runnable myRunnable = new MyRunnable (); Thread Thread = novo mythread (myRunnable); thread.start (); }}}} classe myRunnable implementa runnable {private int i = 0; @Override public void run () {System.out.println ("In MyRunnable Run"); for (i = 0; i <100; i ++) {System.out.println (thread.currentThread (). getName () + "" + i); }}} classe mythread estende thread {private int i = 0; public mythread (runnable runnable) {super (runnable); } @Override public void run () {System.out.println ("In Mythread Run"); for (i = 0; i <100; i ++) {System.out.println (thread.currentThread (). getName () + "" + i); }}}Da mesma forma, o mesmo vale para criar tópicos que implementam a interface executável, a diferença é que
1 thread thread = novo mythread (myRunnable);
Então, esse método pode criar com sucesso um novo thread? A resposta é sim. Quanto ao corpo de execução do thread neste momento, o método run () está na interface Mirunnable ou no método run () na classe Mythread? Através da saída, sabemos que o corpo de execução do encadeamento é o método run () na classe Mythread. De fato, o motivo é muito simples, porque a classe Thread em si também implementa a interface executável e o método run () é definido pela primeira vez na interface executável.
interface pública runnable {public abstrate void run (); } Vamos dar uma olhada na implementação do método run () na interface executável na classe Thread:
@Override public void run () {if (target! = Null) {Target.run (); }}Ou seja, ao executar o método run () na classe Thread, primeiro determinará se o destino existe. Se existir, o método run () no destino é executado, ou seja, o método run () na classe que implementa a interface executável e substitui o método run (). No entanto, nas colunas dadas acima, devido à existência de polimorfismo, o método run () na classe Thread não é executado, mas o tipo de tempo de execução, ou seja, o método run () na classe Mythread é executado diretamente.
3. Crie threads usando interfaces chamáveis e futuras. Especificamente, ele cria uma classe de implementação para a interface chamada e implementa o método clall (). E use a classe FutureTask para envolver o objeto Class de implementação chamável e use este objeto FutureTask como o alvo do objeto Thread para criar um thread.
Parece um pouco complicado, mas ficará claro se você olhar diretamente para um exemplo.
classe pública threadtest {public static void main (string [] args) {callable <Teger> myCallable = new MyCallable (); // Crie objeto MyCallable FutureTask <TEGER> ft = new FutureTask <Integer> (MyCallable); // Use o FutureTask para envolver o objeto MyCallable for (int i = 0; i <100; i ++) {System.out.println (thread.currentThread (). GetName () + "" + i); if (i == 30) {thread thread = new Thread (ft); // Objeto FutureTask cria um novo thread como um alvo do thread objeto Thread.start (); // O encadeamento entra no estado pronto}} System.out.println ("O encadeamento principal para loop foi executado .."); tente {int sum = ft.get (); // Obtenha o resultado retornado pelo método Call () no recém -criado New Thread System.out.println ("Sum =" + Sum); } catch (interruptedException e) {e.printStackTrace (); } catch (ExecutionException e) {e.printStackTrace (); }}} classe MyCallable implementa Callable <Teger> {private int i = 0; // Ao contrário do método run (), o método Call () possui um valor de retorno @Override Public Integer Call () {int Sum = 0; para (; i <100; i ++) {System.out.println (thread.currentThread (). getName () + "" + i); soma += i; } retornar soma; }}Primeiro de tudo, descobrimos que, ao implementar a interface chamada, o método run () não é mais o método run (), mas o método Call (). Este método Call () é o corpo de execução do thread e também tem um valor de retorno! Ao criar um novo thread, o objeto MyCallable é embrulhado através do FutureTask e também serve como um alvo para o objeto Thread. Em seguida, observe a definição da classe FutureTask:
classe pública FutureTask <V> implementa RunnableFuture <V> {// ....} interface pública runnablefuture <V> estende Runnable, Future <V> {void run (); }Portanto, descobrimos que a classe FutureTask implementa interfaces executáveis e futuras, o que faz com que as características duplas do futuro e da execução. Através do recurso Runnable, ele pode ser usado como um alvo do objeto Thread, e o recurso futuro permite obter o valor de retorno do método Call () no thread recém -criado.
Depois de executar este programa, descobrimos que a soma = 4950 é sempre a última saída. "O encadeamento principal do loop foi executado ..." É provável que seja emitido no meio do loop de rosca infantil. Do mecanismo de agendamento de threads da CPU, sabemos que não há problema com o tempo de saída de "o encadeamento principal para o loop foi executado ...", então por que soma = 4950 será a saída para sempre?
O motivo é que, quando o método Call () do encadeamento da criança é obtido através do método ft.get (), quando o método do thread da criança ainda não foi executado, o método ft.get () bloqueará até que o método Call () seja executado antes que o valor de retorno possa ser obtido.
O acima explica principalmente três métodos de criação de roscas comuns. Para a inicialização dos threads, todos eles são chamados de método start () do objeto Thread. É importante observar que o método start () não pode ser chamado duas vezes no mesmo objeto de encadeamento.
Iii. Status pronto, de corrida e morte do Java Multithreading
O estado pronto é convertido para o estado em execução: quando este thread obtém o recurso do processador;
O estado de corrida é convertido para o estado pronto: quando esse thread chama ativamente o método de rendimento () ou perde os recursos do processador durante a execução.
O estado de corrida é convertido para o estado morto: quando o órgão de execução do thread é concluído ou ocorre uma exceção.
Deve -se notar aqui que, quando o método de rendimento () do encadeamento é chamado, o encadeamento transita do estado em execução para o estado pronto, mas que encadeamento no estado pronto da CPU está agendado tem uma certa aleatoriedade. Portanto, pode ocorrer que, depois que o encadeamento A chama o método de rendimento (), a CPU ainda agenda o encadeamento A.
Devido às necessidades comerciais reais, é frequentemente encontrado que um tópico precisa ser encerrado em uma oportunidade específica para fazê -lo entrar em um estado morto. O método mais comum no momento é definir uma variável booleana e, quando as condições forem atendidas, o corpo de execução do encadeamento será executado rapidamente. como:
classe pública threadtest {public static void main (string [] args) {myRunnable myRunnable = new MyRunnable (); Thread Thread = novo thread (myRunnable); for (int i = 0; i <100; i ++) {System.out.println (thread.currentThread (). getName () + "" + i); if (i == 30) {thread.start (); } if (i == 40) {myRunnable.stopthread (); }}}} classe MyRunnable implementa Runnable {Stop Private Boolean; @Override public void run () {for (int i = 0; i <100 &&! Stop; i ++) {System.out.println (thread.currentThread (). GetName () + "" + i); }} public void stopThread () {this.stop = true; }}Continuaremos a resolver artigos relacionados no futuro. Obrigado pelo seu apoio a este site!
Série de artigos:
Explicação das instâncias multi-threaded java (i)
Explicação detalhada das instâncias multi-thread Java (ii)
Explicação detalhada das instâncias multi-threaded Java (iii)