O título é o seguinte:
classe pública TestSync2 implementa Runnable {int b = 100; Void sincronizado m1 () lança interruptedException {b = 1000; Thread.sleep (500); // 6 system.out.println ("b =" + b); } Sincronizado void m2 () lança interruptedException {thread.sleep (250); // 5 b = 2000; } public static void main (string [] args) lança interruptedException {testsync2 tt = new testsync2 (); Thread t = novo thread (tt); // 1 t.start (); // 2 tt.m2 (); // 3 System.out.println ("Thread principal B =" + tt.b); // 4} @Override public void run () {try {m1 (); } catch (interruptedException e) {e.printStackTrace (); }}}O resultado da saída deste programa?
Resultados da saída do programa
Tópico principal B = 2000b = 1000
ou
Tópico principal B = 1000b = 1000
Verifique os pontos de conhecimento
Em Java, os programas com vários threads são os mais difíceis de entender e depurar. Muitas vezes, os resultados da execução não são executados como imaginamos. Portanto, é muito difícil de multi-thread em Java. Lembro -me vagamente de quando estava levando o nível 2 de idioma C na faculdade, qual é a pergunta no ++ e muitos outros níveis prioritários correspondem aos resultados finais da saída. Quero ter algumas perguntas de prioridade e combinação para esse tipo de pergunta. Basta recitá-lo apoiando-o, mas o Java multi-thread ainda precisa ser bem compreendido, o encosto não pode ser feito.
Vamos iniciar uma breve análise:
Esta pergunta envolve 2 threads (encadeamento principal, encadeamento filho) e as palavras -chave envolvem sincronizado e thread.sleep.
A palavra -chave sincronizada ainda é bastante complicada (às vezes eu não entendo bem, então a pergunta acima tem alguns mal -entendidos). Sua função é realizar a sincronização do encadeamento (existem muitos métodos para implementar a sincronização do encadeamento, é apenas um tipo de outra coisa que os artigos de acompanhamento falarão. Algumas implementações do mestre Doug Lea precisam ser estudadas com cuidado). Seu trabalho é bloquear o código que precisa de sincronização, para que apenas um thread possa entrar no bloco de sincronização por vez (na verdade, é uma estratégia pessimista) para garantir que o thread se lembre de segurança.
O uso da palavra -chave geral sincronizada
No código acima, o uso de sincronizado realmente pertence ao segundo caso. Atuando diretamente no método da instância: é equivalente a bloquear a instância atual. Antes de inserir o código de sincronização, você deve obter o bloqueio da instância atual.
Possíveis mal -entendidos
1. Como não entendemos sincronizados, muitas vezes, operamos um método sincronizado por multi-threading. Quando dois threads chamam 2 métodos sincronizados diferentes, pensa -se que é irrelevante. Essa ideia é mal -entendida. Atuando diretamente no método da instância: é equivalente a bloquear a instância atual. Antes de inserir o código de sincronização, você deve obter o bloqueio da instância atual.
2. Se um método sincronizado for chamado. Outra chamada para um método normal não tem nada a fazer, e os dois não têm um relacionamento de espera.
Estes são muito úteis para a análise subsequente.
Thread.sleep
Segure o encadeamento atual (ou seja, o thread que chama o método) por um período de tempo, dando a outros threads a chance de continuar a execução, mas não libera o bloqueio do objeto. Ou seja, se a sincronização sincronizada for rápida, outros threads ainda não podem acessar dados compartilhados. Observe que esse método precisa capturar exceções, o que é muito útil para a análise subsequente.
Processo de análise
O Java é executado a partir do método principal. Dizem que existem 2 threads, mas mesmo se você modificar a prioridade do thread aqui, é inútil. A prioridade é somente quando os dois programas ainda não foram executados. Agora, uma vez executado esse código, o thread principal foi executado. Para a variável de atributo int b = 100, não haverá problema de visibilidade porque o sincronizado é usado (e não há necessidade de dizer que a declaração volátil é usada), ao executar a etapa 1 (thread t = new Thread (tt); // 1), o encadeamento está em novo estado e ainda não começou a funcionar. Quando as duas etapas são executadas (t.start (); // 2) Quando o método de início é chamado, o thread é realmente iniciado e entra no estado executável. O estado executável significa que ele pode ser executado e tudo está pronto, mas não significa que deve ser executado na CPU. Se existe uma execução real depende da programação da CPU de serviço. Aqui, ao executar as três etapas, você deve primeiro obter o bloqueio (porque o início precisa chamar o método nativo, e tudo está pronto após a conclusão do uso, mas isso não significa que ele deve ser executado na CPU. Se houver uma execução real depende da programação da CPU do serviço e, em seguida, o método de execução será chamado e o método M1 será executado). De fato, não importa se o thread.Sheep nos dois métodos sincronizados é, provavelmente acrescenta dificuldade em confusão. Quando as três etapas são executadas, o thread infantil está realmente pronto em breve, mas como o sincronizado existe e atua como o mesmo objeto, o thread infantil precisa esperar. Como a ordem de execução no método principal é executada sequencialmente, ela deve ser concluída após a execução da etapa 3 antes que a 4ª etapa possa ser alcançada. Como a execução da etapa 3 é concluída, o thread infantil pode executar o M1. Há um problema aqui que quem recebe o multi-thread primeiro. Se as 4 etapas forem obtidas primeiro, o encadeamento principal B = 2000. Se o encadeamento infantil M1 for obtido, B poderá ter sido atribuído a 1000 ou antes da atribuição das 4 etapas, o resultado possível é o encadeamento principal B = 1000 ou o encadeamento principal B = 2000. Se as 6 etapas forem removidas aqui, B = Executar antes e o encadeamento principal B = antes é incerto. No entanto, como existem 6 etapas, não importa o quê, o encadeamento principal B = está na frente, depende da situação se for igual a 1000 ou 2000. Depois disso, B = 1000 é definitivamente corrigido.
Algumas sugestões para multi-threading
Existem também algumas dicas para compartilhar os artigos subsequentes. Multi-threading é particularmente importante e difícil. Espero que todos gastem mais tempo com isso.
Algumas técnicas de depuração para multithreading
Devido a pontos de interrupção, todos os threads precisam parar ao passar por pontos de interrupção, o que faz com que esse ponto seja interrompido constantemente, o que é muito desconfortável. Existem pontos de interrupção condicional no eclispe e você pode parar quando as condições forem atendidas, então isso é conveniente.
Resumir
O exposto acima é a pergunta mais difícil da entrevista em Java na história que o editor apresentou a você. Espero que seja útil para você. Se você tiver alguma dúvida, deixe -me uma mensagem e o editor responderá a você a tempo. Muito obrigado pelo seu apoio ao site wulin.com!