Quando uma palavra -chave da linguagem Java é usada para modificar um método ou um bloco de código, ela pode garantir que, no máximo, um thread execute o código ao mesmo tempo.
1. Quando dois threads simultâneos acessam este bloco de código sincronizado (this) sincronizado no mesmo objeto, apenas um thread pode ser executado dentro de um tempo. Outro thread deve esperar que o encadeamento atual execute este bloco de código antes de poder executar o bloco de código.
2. No entanto, quando um thread acessa um bloco de código de sincronização sincronizado (this) de um objeto, outro thread ainda pode acessar o bloco de código de sincronização não sincronizado (this) nesse objeto.
3. É particularmente crítico que, quando um encadeamento acessar um bloco de código de sincronização sincronizado (this) de um objeto, outros threads bloquearão o acesso a todos os outros blocos de sincronização sincronizados (this) de sincronização no objeto.
4. O terceiro exemplo também se aplica a outros blocos de código síncrono. Ou seja, quando um thread acessa um bloco de código de sincronização sincronizado (this) de um objeto, ele obtém a trava do objeto desse objeto. Como resultado, outros threads acesso a todas as partes do código síncrono do objeto objeto são temporariamente bloqueados.
5. As regras acima também se aplicam a outros bloqueios de objetos.
Dê um exemplo:
1. Quando dois threads simultâneos acessam este bloco de código sincronizado (this) sincronizado no mesmo objeto, apenas um thread pode ser executado dentro de um tempo. Outro thread deve esperar que o encadeamento atual execute este bloco de código antes de poder executar o bloco de código.
pacote ths; public class Thread1 implementa runnable {public void run () {sincronizado (this) {for (int i = 0; i <5; i ++) {System.out.println (thread.currentThread (). getName () + "synchronized loop" + i); }}} public static void main (string [] args) {thread1 t1 = new Thread1 (); Thread ta = novo thread (t1, "a"); Thread tb = novo thread (t1, "b"); ta.start (); tb.start (); }}resultado:
Um loop sincronizado 0
Um loop sincronizado 1
Um loop sincronizado 2
Um loop sincronizado 3
Um loop sincronizado 4
B loop sincronizado 0
B loop sincronizado 1
B Loop Syncronizado 2
B loop sincronizado 3
B loop sincronizado 4
2. No entanto, quando um thread acessa um bloco de código de sincronização sincronizado (this) de um objeto, outro thread ainda pode acessar o bloco de código de sincronização não sincronizado (this) nesse objeto.
pacote ths; public class Thread2 {public void m4t1 () {sincronizado (this) {int i = 5; while (i--> 0) {System.out.println (thread.currentThread (). getName () + ":" + i); tente {thread.sleep (500); } catch (interruptedException ie) {}}}} public void m4t2 () {int i = 5; while (i--> 0) {System.out.println (thread.currentThread (). getName () + ":" + i); tente {thread.sleep (500); } catch (interruptedException ie) {}}} public static void main (string [] args) {final Thread2 myt2 = new Thread2 (); Thread t1 = new Thread (new Runnable () {public void run () {myt2.m4t1 ();}}, "t1"); Thread t2 = novo thread (novo runnable () {public void run () {myt2.m4t2 ();}}, "t2"); t1.start (); t2.start (); }} resultado:
T1: 4
T2: 4
T1: 3
T2: 3
T1: 2
T2: 2
T1: 1
T2: 1
T1: 0
T2: 0
3. É particularmente crítico que, quando um encadeamento acessar um bloco de código de sincronização sincronizado (this) de um objeto, outros threads bloquearão o acesso a todos os outros blocos de sincronização sincronizados (this) de sincronização no objeto.
// modificar thread2.m4t2 () Método: public void m4t2 () {sincronizado (this) {int i = 5; while (i--> 0) {System.out.println (thread.currentThread (). getName () + ":" + i); tente {thread.sleep (500); } catch (interruptedException ie) {}}}}resultado:
T1: 4
T1: 3
T1: 2
T1: 1
T1: 0
T2: 4
T2: 3
T2: 2
T2: 1
T2: 0
4. O terceiro exemplo também se aplica a outros blocos de código síncrono. Ou seja, quando um thread acessa um bloco de código de sincronização sincronizado (this) de um objeto, ele obtém a trava do objeto desse objeto. Como resultado, outros threads acesso a todas as partes do código síncrono do objeto objeto são temporariamente bloqueados.
// modifica o método Thread2.m4t2 () da seguinte forma: public sincronizado void m4t2 () {int i = 5; while (i--> 0) {System.out.println (thread.currentThread (). getName () + ":" + i); tente {thread.sleep (500); } catch (interruptedException ie) {}}} resultado:
T1: 4
T1: 3
T1: 2
T1: 1
T1: 0
T2: 4
T2: 3
T2: 2
T2: 1
T2: 0
5. As regras acima também se aplicam a outros bloqueios de objetos:
pacote ths; classe pública thread3 {classe interna {private void m4t1 () {int i = 5; while (i--> 0) {System.out.println (thread.currentThread (). getName () + ": interna.m4t1 () =" + i); tente {thread.sleep (500); } catch (interruptedException ie) {}}} private void m4t2 () {int i = 5; while (i--> 0) {System.out.println (thread.currentThread (). getName () + ": interna.m4t2 () =" + i); tente {thread.sleep (500); } catch (interruptedException ie) {}}}} private void m4t1 (interno interno) {synchronized (interno) {// use o bloqueio de objeto interno.m4t1 (); } private void m4t2 (interno interno) {Inner.m4t2 (); } public static void main (string [] args) {final Thread3 myt3 = new Thread3 (); final interno interno = myt3.new interno (); Thread t1 = novo thread (new Runnable () {public void run () {myt3.m4t1 (interno);}}, "t1"); Thread t2 = novo thread (novo runnable () {public void run () {myt3.m4t2 (interno);}}, "t2"); t1.start (); t2.start (); }}resultado:
Embora o Thread T1 obtenha um bloqueio de objeto no interno, pois o thread T2 acessa a parte assíncrona no mesmo interno. Portanto, os dois threads não interferem entre si.
T1: Inner.m4t1 () = 4
T2: Inner.M4T2 () = 4
T1: Inner.M4T1 () = 3
T2: Inner.M4T2 () = 3
T1: Inner.m4t1 () = 2
T2: Inner.M4T2 () = 2
T1: Inner.m4t1 () = 1
T2: Inner.m4t2 () = 1
T1: Inner.m4t1 () = 0
T2: Inner.M4T2 () = 0
Agora colocado sincronizado na frente do interno.m4t2 ():
Void sincronizado privado m4t2 () {int i = 5; while (i--> 0) {System.out.println (thread.currentThread (). getName () + ": interna.m4t2 () =" + i); tente {thread.sleep (500); } catch (interruptedException ie) {}}}resultado:
Embora os threads T1 e T2 acessem duas partes não relacionadas do mesmo objeto interno, porque o T1 obtém o bloqueio do objeto no interno, o acesso do T2 ao Inner.M4T2 () também é bloqueado porque M4T2 () é um método de sincronização no interior.
T1: Inner.m4t1 () = 4
T1: Inner.M4T1 () = 3
T1: Inner.m4t1 () = 2
T1: Inner.m4t1 () = 1
T1: Inner.m4t1 () = 0
T2: Inner.M4T2 () = 4
T2: Inner.M4T2 () = 3
T2: Inner.M4T2 () = 2
T2: Inner.m4t2 () = 1
T2: Inner.M4T2 () = 0
Artigo 2:
Palavra -chave sincronizada, que inclui dois usos: o método sincronizado e o bloco sincronizado.
1. Método sincronizado: Declare o método sincronizado adicionando a palavra -chave sincronizada à declaração do método. como:
public sincronizado void AccessVal (int newval);
O método sincronizado controla o acesso às variáveis do membro da classe: cada instância da classe corresponde a um bloqueio e cada método sincronizado deve obter o bloqueio da instância da classe que chama o método antes que ele possa ser executado. Caso contrário, o fio ao qual pertence é bloqueado. Depois que o método for executado, ele ocupará exclusivamente a fechadura. O bloqueio não será liberado até que retorne do método. O encadeamento bloqueado pode obter o bloqueio e entrar novamente no estado executável. Esse mecanismo garante que, ao mesmo tempo, para cada instância da classe, no máximo uma de todas as funções de membro declaradas sincronizadas está em um estado executável (porque no máximo um pode obter o bloqueio correspondente à instância da classe), evitando efetivamente os conflitos de acesso das variáveis de classe (desde que todos os métodos possíveis para acessar os membros da classe varieis sejam declarações declinadas).
Em Java, não apenas as instâncias de classe, mas cada classe também corresponde a um bloqueio, para que possamos declarar a função estática da classe como sincronizada para controlar seu acesso às variáveis estáticas do membro da classe.
A desvantagem do método sincronizado: declarar um grande método como sincronizado afetará bastante a eficiência. Normalmente, se o método da classe Thread Run () for declarado como sincronizado, pois está sendo executado ao longo da vida do thread, isso fará com que nunca tenha sucesso em nenhum método sincronizado desta classe. É claro que podemos resolver esse problema colocando o código que acessa as variáveis do membro da classe em um método especial, declarando -o sincronizado e chamando -o no método principal, mas o Java nos fornece uma solução melhor, ou seja, o bloco sincronizado.
2. Bloco sincronizado: Declare o bloco sincronizado através da palavra -chave sincronizada. A sintaxe é a seguinte:
sincronizado (syncobject) {// código que permite o controle de acesso} O bloco sincronizado é um bloco de código no qual o código deve obter um bloqueio do objeto SyncObject (como mencionado anteriormente, pode ser uma instância ou classe de classe) antes que ele possa ser executado. O mecanismo específico é o mesmo descrito acima. Como pode ser direcionado para qualquer bloco de código e objetos bloqueados podem ser especificados a qualquer momento, é mais flexível.
Alguns entendimentos de sincronizado (this) <br /> 1. Quando dois threads simultâneos acessam este bloco de código sincronizado sincronizado (this) no mesmo objeto, apenas um thread pode ser executado dentro de um período. Outro thread deve esperar que o encadeamento atual execute este bloco de código antes de poder executar o bloco de código.
2. No entanto, quando um thread acessa um bloco de código de sincronização sincronizado (this) de um objeto, outro thread ainda pode acessar o bloco de código de sincronização não sincronizado (this) nesse objeto.
3. É particularmente crítico que, quando um encadeamento acessar um bloco de código de sincronização sincronizado (this) de um objeto, outros threads bloquearão o acesso a todos os outros blocos de sincronização sincronizados (this) de sincronização no objeto.
4. O terceiro exemplo também se aplica a outros blocos de código síncrono. Ou seja, quando um thread acessa um bloco de código de sincronização sincronizado (this) de um objeto, ele obtém a trava do objeto desse objeto. Como resultado, outros threads acesso a todas as partes do código síncrono do objeto objeto são temporariamente bloqueados.
5. As regras acima também se aplicam a outros bloqueios de objetos.
Como usar sincronizado em java
Por exemplo: um objeto é como uma casa grande, a porta está sempre aberta. Existem muitos quartos na casa (ou seja, o método).
Essas salas foram bloqueadas (método sincronizado) e não estão bloqueadas (método normal). Há uma chave na porta, que pode abrir todos os quartos trancados.
Além disso, comparo todos os tópicos que desejam chamar o método de objeto para pessoas que desejam entrar em uma sala nesta casa. Existem tantas coisas, vamos ver como essas coisas funcionam.
Aqui, primeiro esclarecemos nossos pré -requisitos. O objeto possui pelo menos um método sincronizado, caso contrário, qual é o objetivo dessa chave? Obviamente, não haverá esse tópico para nós.
Um homem queria entrar em uma sala trancada. Ele chegou à porta da casa e viu a chave lá (isso significa que ninguém mais quer usar a sala trancada ainda). Então ele subiu e pegou as chaves e usou os quartos enquanto planejava. Esteja ciente de que ele retornará a chave imediatamente após o uso da sala trancada todas as vezes. Mesmo que ele queira usar dois quartos trancados seguidos, ele retornará as chaves para recuperá -las. Portanto, o princípio de usar uma chave nos casos comuns é: "peça emprestado conforme você usa e devolva assim que a usar".
Neste momento, outras pessoas podem usar os quartos desbloqueados sem restrições. Uma pessoa pode usar uma sala e duas pessoas podem usar um quarto, sem restrições. Mas se alguém quiser entrar em uma sala trancada, ele precisa correr para o portão para dar uma olhada. Obviamente, se você tiver a chave, você sairá. Se você não tiver, só pode esperar. Se muitas pessoas estão esperando por essa chave, quem receberá a chave primeiro após a devolução? Não garantido. Como o cara do exemplo anterior que queria usar dois quartos trancados seguidos, se houvesse outras pessoas esperando as chaves no meio, não havia garantia de que esse cara o recebesse novamente. (The JAVA specification clearly states that it is not guaranteed in many places, such as how long it takes for Thread.sleep() to return to run after rest, the thread with the same priority is executed first, and which thread in the waiting pool will be given priority after the lock to access the object is released, etc. I think the final decision is in the JVM. The reason why it is not guaranteed is because when the JVM makes the above decision, it is by no means simply making a judgment com base em uma condição, mas com base em muitos artigos.
Como existem muitas condições de julgamento, se você diz, isso pode afetar a promoção do Java, ou pode ser devido à proteção da propriedade intelectual. Sun me deu uma promessa e passou por isso. Não há nada de errado com isso. Mas acredito que essas incertezas não são totalmente incertas. Porque o próprio computador é executado de acordo com as instruções. Mesmo que o fenômeno pareça aleatório, é realmente regular. Qualquer pessoa que tenha estudado computadores sabe que o nome científico de números aleatórios em computadores são números pseudo-aleatórios, que são escritos por pessoas que usam determinados métodos, e eles parecem aleatórios. Além disso, talvez seja porque é muito difícil ter certeza e não muito significativo; portanto, se você não tiver certeza, não tem certeza. )
Vamos dar uma olhada no bloco de código de sincronização. Há uma pequena diferença do método de sincronização.
1. Em termos de tamanho, o bloco de código de sincronização é menor que o método de sincronização. Você pode pensar no bloco de código de sincronização como um espaço em uma sala desbloqueada separada por uma tela bloqueada.
2. O bloco de código de sincronização também pode especificar artificialmente a chave para obter um certo outro objeto. Assim como especificar qual chave para desbloquear a tela, você pode usar a chave desta sala; Você também pode especificar que a chave de outra casa pode abri -la. Dessa forma, você precisa correr para outra casa para trazer essa chave e usar a chave daquela casa para abrir a tela trancada desta casa.
Lembre -se de que a chave daquela outra casa que você obteve não afeta outras pessoas que entram na sala sem fechaduras naquela casa.
Por que usar blocos de código síncrono? Eu acho que deveria ser assim: antes de tudo, a parte de sincronização do programa tem muito impacto na eficiência da operação, e um método geralmente é criar algumas variáveis locais primeiro e depois fazer algumas operações nessas variáveis, como operações, exibição, etc.; e quanto mais código coberto pela sincronização, mais grave o impacto na eficiência. Portanto, geralmente tentamos restringir seu impacto.
Como fazer isso? Sincronize blocos de código. Sincronizamos apenas os locais de sincronização em um método, como operações.
Além disso, o recurso dos blocos de código síncrono que podem especificar Keys tem uma vantagem adicional, que é que ele pode ocupar as chaves de um objeto dentro de um certo período de tempo. Você se lembra dos princípios de usar chaves em situações comuns mencionadas anteriormente? Não é a situação comum agora. A chave que você obteve nunca é retornada, mas é retornada apenas quando você sai do bloco de código síncrono.
Eu também usei o cara na frente que queria usar dois quartos trancados seguidos para fazer um exemplo. Como posso continuar usando outro depois de usá -lo? Use blocos de código síncrono. Primeiro, crie outro tópico, faça um bloco de código síncrono e aponte o bloqueio desse bloco de código para a chave da casa. Em seguida, inicie esse tópico. Contanto que você possa pegar a chave da casa ao inserir esse bloco de código, você pode mantê -lo até sair desse bloco de código. Em outras palavras, você pode até atravessar todos os quartos trancados nesta sala, ou até dormir (10*60*1000), e ainda existem 1.000 fios esperando por essa chave na porta. Muito agradável.
Aqui falaremos sobre a correlação entre o método Sleep () e a chave. Se um thread for forçado a dormir () depois de obter a chave e não concluiu o conteúdo síncrono, a chave ainda está lá. A chave não será devolvida até que seja executada novamente e conclua todo o conteúdo síncrono. Lembre -se de que esse cara estava cansado de trabalhar, então ele foi fazer uma pausa e não terminou o que ia fazer. Para evitar que outras pessoas entram na sala e fazendo uma bagunça, ele tem que usar a única chave em seu corpo, mesmo quando está dormindo.
Finalmente, algumas pessoas podem perguntar: por que você precisa de uma chave para abrir em vez de uma chave e uma porta? Eu acho que isso é puramente por causa da complexidade. Obviamente, uma chave e uma porta são mais seguras, mas envolverão muitos problemas. A geração, armazenamento, aquisição, devolução, etc. de chaves. Sua complexidade pode aumentar nas sequências geométricas com o aumento do método de sincronização, o que afeta seriamente a eficiência. Isso também é uma troca. O quão indesejável é aumentar um pouco a segurança, resultando em uma redução significativa na eficiência.
Um exemplo simples de sincronizado
classe pública textThread {public static void main (string [] args) {txtThread tt = new txtThread (); novo thread (tt) .start (); novo thread (tt) .start (); novo thread (tt) .start (); novo thread (tt) .start (); }} classe txtThread implementa runnable {int num = 100; String str = new string (); public void run () {synchronized (str) {while (num> 0) {try {thread.sleep (1); } catch (Exceção e) {e.getMessage (); } System.out.println (thread.currentThread (). GetName () + "este é" + num-); }}}}No exemplo acima, para criar uma diferença de tempo, ou seja, a oportunidade de cometer um erro, o Thread.Sleep (10) é usado.
O mecanismo de apoio e sincronização de Java para a multithreading é muito popular. Parece que o uso da palavra -chave sincronizada pode facilmente resolver o problema da sincronização de dados compartilhados multithreaded. O que exatamente? Também é necessário ter uma compreensão profunda do papel das palavras-chave sincronizadas antes que você possa concluir.
Em geral, a palavra -chave sincronizada pode ser usada como um modificador da função ou como uma instrução dentro da função, que é o método de sincronização e o bloco de declaração de sincronização que geralmente são mencionados. Se você classificá -lo com mais cuidado, o sincronizado poderá atuar em variáveis de instância, referências de objetos, funções estáticas e literais de classe (constantes literais de nome de classe).
Antes de elaborar ainda mais, precisamos esclarecer alguns pontos:
A. se a palavra -chave sincronizada é adicionada a um método ou objeto, a trava adquira é um objeto, em vez de tratar um pedaço de código ou função como uma trava, e o método de sincronização provavelmente é ainda mais provável
Acesso ao objeto ao seu tópico.
B. Cada objeto tem apenas um bloqueio associado a ele.
C. A implementação da sincronização requer muita sobrecarga do sistema como um custo e pode até causar impulsos, portanto, tente evitar o controle desnecessário de sincronização.
Em seguida, vamos discutir o impacto do sincronizado usando diferentes lugares no código:
Supondo que P1 e P2 sejam objetos diferentes da mesma classe, esta classe define blocos de sincronização ou métodos de sincronização nas situações a seguir, e P1 e P2 podem chamá -los.
1. Quando sincronizado é usado como um modificador de função, o código de exemplo é o seguinte:
Public sincronizado void Metodaaa () {//….}Este é o método de sincronização. Então, qual objeto é sincronizado bloqueado neste momento? O que ele trava é chamar esse objeto de método síncrono. Ou seja, quando um objeto P1 executa esse método de sincronização em diferentes encadeamentos, a exclusão mútua será formada entre eles para alcançar o efeito da sincronização. No entanto, outro objeto P2 gerado pela classe à qual esse objeto pertence pode chamar arbitrariamente esse método com a palavra -chave sincronizada adicionada.
O código de exemplo acima é equivalente ao seguinte código:
public void Methodaaa () {sincronizado (this) // (1) {//… ..}}(1) O que significa isso no ponto? Refere -se ao objeto que chama esse método, como P1. Pode -se observar que o método de sincronização é essencialmente para aplicar sincronizado à referência do objeto. Somente o encadeamento que obteve o bloqueio do objeto P1 pode chamar o método de sincronização P1. Para P2, a trava P1 não tem nada a ver com isso. O programa também pode se livrar do controle do mecanismo de sincronização nessa situação, causando confusão de dados: (
2 Sincronizar blocos, o código de amostra é o seguinte:
Public void Method3 (SomeObject So) {sincronizado (So) {//… ..}}Neste momento, o bloqueio é o objeto de So. Quem recebe o bloqueio pode executar o código que controla. Quando existe um objeto claro como um bloqueio, você pode escrever o programa como esse, mas quando não há objeto claro como um bloqueio e só deseja que um pedaço de código sincronize, você pode criar uma variável de instância especial (ele deve ser um objeto) para agir como um bloqueio:
classe Foo implementa Runnable {private byte [] Lock = new Byte [0]; // Variável de instância especial public void Metoda () {Sincronizada (Lock) {//…}} //… ..}NOTA: Os objetos de matriz de bytes de comprimento zero são mais econômicos do que qualquer objeto para criar um código de byte compilado: apenas 3 códigos de operação são necessários para gerar um objeto de byte de comprimento zero [], enquanto o objeto Lock = new Object () requer 7 opcodes.
3. Use sincronizado à função estática, o código de exemplo é o seguinte:
Classe foo {public sincronizado estático void Metodaaa () // Função estática sincronizada {//…. } public void methodbbb () {sincronizado (foo.class) // class Literal (classe literal constant)}}O método Methodbbb () no código usa a classe literal como um bloqueio. Tem o mesmo efeito que a função estática sincronizada. A fechadura obtida é muito especial. É a classe à qual o objeto atualmente chamando esse método pertence (classe, não um objeto específico gerado por esta classe).
Lembro que no livro "Java eficaz", vi que usar foo.class e p1.getclass () como bloqueios síncronos é diferente, e p1.getclass () não pode ser usado para alcançar o objetivo de travar essa classe. P1 refere -se a um objeto gerado pela classe Foo.
Pode -se inferir que, se uma classe define uma função estática sincronizada A e uma função de instância sincronizada B, o mesmo objeto obj dessa classe não constituirá sincronização ao acessar dois métodos A e B em vários threads, porque suas fechaduras são diferentes. A fechadura do método A é o objeto Obj, enquanto a fechadura de B é a classe à qual o OBJ pertence.
O resumo é o seguinte:
Descobrir quais bloqueios sincronizados de objetos podem nos ajudar a projetar programas com vários threads seguros. Há também algumas dicas para tornar o acesso síncrono aos recursos compartilhados mais seguros:
1. Defina a variável de instância do método privado + seu método GET, em vez da variável de instância do público/protegido. Se uma variável for definida como pública, o objeto poderá ignorar o controle do método de sincronização e obtê -lo diretamente e alterá -lo. Este também é um dos métodos de implementação padrão do Javabean.
2. Se a variável de instância for um objeto, como uma matriz ou uma lista de Arraylist, o método acima ainda é inseguro, porque quando um objeto externo recebe a referência ao objeto de instância através do método GET e o aponta para outro objeto, a variável privada mudará, o que não é muito perigoso. No momento, você precisa adicionar sincronizar ao método GET e retornar apenas o clone () deste objeto privado, para que o chamador receba a referência à cópia do objeto
O exposto acima é todo o conteúdo deste artigo. Espero que seja útil para o aprendizado de todos e espero que todos apoiem mais o wulin.com.