Na programação multithread, a questão mais crítica e mais preocupada deve ser a questão da sincronização, que é um ponto difícil e o núcleo.
Do pacote Syncronized and Volátil da versão mais antiga do JDK, até a interface de bloqueio no pacote java.util.concurrent.locks fornecido no JDK 1.5 (as implementações incluem readlock, writelock e reentrantlock), a implementação de leitura múltipla também está em maturação gradualmente.
Qual mecanismo é usado para controlar a sincronização? A primeira reação é o bloqueio, que deveria ter sido exposto ao aprender o sistema operacional e o banco de dados. Nos programas Java Multi-Thread, quando vários programas competem pelo mesmo recurso, a fim de evitar a corrosão dos recursos, o primeiro thread acessando o recurso recebe um bloqueio de objeto e as gerações posteriores precisam aguardar a liberação desse bloqueio de objeto.
Sim, a coisa mais preocupada com a sincronização dos threads java é o uso de recursos compartilhados.
Vamos primeiro entender alguns recursos compartilhados de quais tópicos estão disponíveis.
Na JVM, precisamos coordenar os dados compartilhados pelos threads:
1. A variável de instância salva na pilha; 2. A variável de classe salva na área do método.
Quando a máquina virtual Java carrega uma classe, cada objeto ou classe estará associado a um monitor para proteger a variável de instância do objeto ou a variável de classe; Obviamente, se o objeto não tiver variáveis de instância ou a classe não possui variáveis, o monitor não monitorará nada.
Para alcançar o mutex dos monitores mencionados acima, a máquina virtual associa um bloqueio (também chamado de bloqueio invisível) para cada objeto ou classe. Deixe -me explicar aqui que os bloqueios de classe também são implementados através de bloqueios de objetos, porque quando a classe é carregada, a JVM criará uma instância de java.lang.class para cada classe; Portanto, quando o bloqueio é contra um objeto, o objeto de classe desta classe está bloqueado.
Além disso, um encadeamento pode bloquear um objeto várias vezes, o que corresponde a várias liberações; É uma calculadora de bloqueio fornecida pela JVM para cada bloqueio de objeto. O último bloqueio é adicionado 1 e o correspondente menos 1, e quando o valor da calculadora é 0, ele é liberado. Esse bloqueio de objeto é usado pelo monitor dentro da JVM e também é gerado automaticamente pela JVM. Todos os programadores não precisam adicioná -lo sozinho.
Depois de introduzir o princípio de sincronização do Java, chegaremos ao tópico e primeiro falaremos sobre o uso do sincronizado. Outras sincronizações serão introduzidas nos capítulos seguintes.
Vamos tentar executar um exemplo primeiro.
pacote thread_test; / *** Teste programas multithread que estendem a implementação da classe de thread**/ public class TestThread estende o thread {private int threadnum; public testthread (int threadnum) {this.threadnum = threadnum; } @Override public sincronizado void run () {for (int i = 0; i <1000; i ++) {System.out.println ("Não." + Threadnum + ":" + i); }} public static void main (string [] args) lança exceção {for (int i = 0; i <10; i ++) {new testThread (i) .start (); Thread.sleep (1); }}}
Resultados em execução:
No.0: 887 No.0: 888 No.0: 889 No.0: 890 No.0: 891 No.0: 892 No.0: 893 No.0: 894 No.7: 122 No.7: 123 No.7: 124
O exposto acima é apenas um clipe, explicando um problema.
Se você tiver cuidado, descobrirá que o No.0: 894 é seguido pelo No.7: 122, o que significa que ele não começa de 0 a 999.
Dizem que o sincronizado pode implementar métodos de sincronização ou blocos de sincronização, por que não pode funcionar aqui?
Vamos primeiro analisar o mecanismo de sincronização. A sincronização é alcançada através do bloqueio. Então, no exemplo acima, qual objeto está bloqueado ou qual classe está bloqueada? Existem duas variáveis dentro, uma é eu e a outra é Threadnum; Eu sou interno ao método, e Threadnum é privado.
Vamos aprender sobre o mecanismo de corrida de sincronizado:
Em um programa Java, quando o bloqueio sincronizado ou o método sincronizado é usado, esta área é marcada para monitoramento; Quando uma JVM lida com o programa, quando um programa entra na área de monitoramento, ele bloqueia automaticamente o objeto ou a classe.
Então, no exemplo acima, o que é bloqueado após a utilização da palavra -chave sincronizada?
Quando o método sincronizado, bloqueie o objeto de instância que chama o próprio método como o bloqueio do objeto. Neste exemplo, os 10 threads têm seus próprios objetos de classe TestThread; portanto, o bloqueio de objeto adquirido também é seu próprio travamento de objetos e não tem nada a ver com outros threads.
Para implementar o bloqueio de métodos, objetos compartilhados devem ser bloqueados.
Altere o exemplo acima e dê uma olhada:
pacote thread_test; / *** Teste programas multithread que estendem a implementação da classe de thread**/ public class TestThread estende o thread {private int threadnum; sinalizador privado de string; // Mark public testthread (int threadnum, string sinalizador) {this.threadnum = threadnum; this.flag = sinalizador; } @Override public void run () {Synchronized (flag) {for (int i = 0; i <1000; i ++) {System.out.println ("no." + Threadnum + ":" + i); }}} public static void main (string [] args) lança exceção {string sinalizador = new String ("sinalizador"); for (int i = 0; i <10; i ++) {new testThread (i, sinalizador) .start (); Thread.sleep (1); }}}
Isso também é adicionado uma bandeira compartilhada. Em seguida, o sinalizador é sincronizado através do bloco sincronizado; Isso atende às condições para bloquear o objeto compartilhado.
Sim, os resultados em execução chegaram em ordem.
Através do bloco sincronizado, especifique a aquisição de bloqueios de objetos para obter sincronização. Então, existem outros métodos que podem ser implementados através do método sincronizado?
De acordo com o princípio da sincronização: se um bloqueio de objeto compartilhado ou trava de classe puder ser obtido, a sincronização poderá ser alcançada. Então, podemos alcançá -lo compartilhando uma trava de classe?
Sim, podemos usar métodos de sincronização estática. De acordo com as características dos métodos estáticos, ele apenas permite que o próprio objeto de classe seja chamado e não pode ser chamado instantando um objeto de classe. Então, se você obtiver o bloqueio deste método estático, obterá o bloqueio da classe e esse bloqueio de classe é o TestThread Locks, e o objetivo de obter os bloqueios de classe compartilhada é alcançado.
O código de implementação é o seguinte:
pacote thread_test; / ** * Teste programas multi-thread que estendem a implementação da classe de thread * * @Author Ciding * @CreateTime 7 de dezembro de 2011 9:37:25 * */ classe pública Testthread estende thread {private int threadnum; public testthread (int threadnum) {this.threadnum = threadnum; } public static sincronizado void statictest (int threadnum) {for (int i = 0; i <1000; i ++) {System.out.println ("no." + threadnum + ":" + i); }} public static void main (string [] args) lança exceção {for (int i = 0; i <10; i ++) {new testThread (i) .start (); Thread.sleep (1); }} @Override public void run () {statictest (Threadnum); }} O resultado da execução é omitido, o mesmo que no segundo exemplo.
O conteúdo acima explica principalmente dois problemas: blocos de sincronização e métodos de sincronização.
1. Bloco sincronizado: o bloqueio do objeto adquirido é o bloqueio do objeto de sinalizador em sincronizado (sinalizador).
2. Método de sincronização: o objeto de classe ao qual o método pertence e o bloqueio do objeto de classe.
O método de sincronização estática será definitivamente sincronizado, pois vários threads serão compartilhados.
Em vez de métodos de sincronização estática, eles serão sincronizados apenas no modo singleton.