Este artigo descreve a diferença entre sincronizado (bloqueio de objeto) e sincronizado estático (bloqueio de classe) em Java. Compartilhe -o para sua referência, como segue:
A diferença entre sincronizado e sincronizado estático
Ao analisar a análise desses dois usos, podemos entender o conceito de bloqueio em Java. Um é um bloqueio de instância (bloqueado em um objeto de instância. Se a classe é um singleton, o bloqueio também possui o conceito de um bloqueio global) e o outro é um bloqueio global (o bloqueio é direcionado para uma classe. Não importa quantos objetos seja a instância, os encadeamentos compartilham o bloqueio). O bloqueio da instância corresponde à palavra -chave sincronizada, enquanto o bloqueio da classe (bloqueio global) corresponde ao sincronizado estático (ou bloqueado no objeto de classe ou carregador de classe da classe).
O artigo a seguir fornece um bom resumo:
1. A diferença entre sincronizado e sincronizado estático
Bloqueia sincronizada A instância atual (objeto atual) da classe para impedir que outros threads acessem todos os blocos sincronizados da instância da classe ao mesmo tempo. Observe que esta é a "instância atual da classe". Não existe tal restrição em dois casos diferentes da classe.
Em seguida, o sincronizado estático controla o acesso simultâneo de todas as instâncias da classe, e o sincronizado estático restringe todas as instâncias da classe em multi-threads para acessar o bloco de código correspondente à classe na JVM ao mesmo tempo. De fato, se houver sincronizado em um método ou um bloco de código em uma classe, depois de gerar uma instância da classe, a instância também terá um bloco de monitoramento para impedir que os threads acessem simultaneamente o bloco de proteção sincronizado da instância. O sincronizado estático é um bloco de monitoramento comum a todas as instâncias da classe. Esta é a diferença entre os dois. Em outras palavras, o sincronizado é equivalente a isso. (Endereçado mais tarde)
Um autor japonês, o "Java Multithreaded Design Pattern", de Jie Chenghao, tem uma coluna como esta:
classe pulbic something () {public sincronizado void ISSynca () {} public sincronizado void ISSyncb () {} public static sincronizado void csyncA () {} public sincronizado estático void csyncb () {}}}Então, se houver duas instâncias x e y de algo de classe, qual é o caso em que o seguinte grupo de métodos é acessado simultaneamente por vários threads?
axissynca () e x.issyncb ()
bxissynca () e y.issynca ()
CXCSYNCA () e Y.CSYNCB ()
dxissynca () e algo.csynca ()
Aqui, está claro que pode ser julgado:
A, todos são acessos de domínio sincronizado à mesma instância (x) e, portanto, não podem ser acessados simultaneamente. (Diferentes domínios sincronizados que acessarem x em multithreads não podem ser acessados simultaneamente)
Se o x.issynca () for acessado em vários threads, porque ainda é a mesma instância e bloqueado no mesmo método, ele não poderá ser acessado em vários threads ao mesmo tempo. (O mesmo domínio sincronizado que acessa X em multithreads não pode ser acessado ao mesmo tempo)
B, é para diferentes casos, por isso pode ser acessado ao mesmo tempo (os bloqueios de objetos não têm restrições de bloqueio para diferentes instâncias de objetos)
C, como é sincronizado estático, diferentes instâncias ainda serão restringidas, o que é equivalente a algo.ISSYNCA () e SOGHT.ISSYNCB (), por isso não pode ser acessado ao mesmo tempo.
Então, e D?, A resposta no livro pode ser acessada simultaneamente. A razão para a resposta é que o Synchronzied é que o método da instância e o método da classe sincronizados são diferentes da trava.
A análise pessoal significa que sincronizado e sincronizado estático são equivalentes a duas gangues, cada uma com seu próprio controle, e não há restrições umas nas outras e podem ser acessadas ao mesmo tempo.
Por exemplo:
classe pública testsynchronized {public sincronizado void test1 () {int i = 5; while (i--> 0) {System.out.println (thread.currentThread (). getName () + ":" + i); tente {thread.sleep (500); } catch (interruptedException ie) {}}} public static sincronizado void test2 () {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 testsynchronized myt2 = new testsynchronized (); Thread test1 = new Thread (novo runnable () {public void run () {myt2.test1 ();}}, "test1"); Thread test2 = new Thread (new runnable () {public void run () {testsynchronized.test2 ();}}, "test2"); test1.start (); test2.start (); // testRunnable tr = new testRunnable (); // thread test3 = novo thread (tr); // test3.start (); }}Test1: 4 Test2: 4 Test1: 3 Test2: 3 Test2: 2 Test1: 2 Test2: 1 Test1: 1 Test1: 0 Test2: 0
O código acima sincronizado modifica o método estático e o método da instância ao mesmo tempo, mas os resultados em execução são executados alternadamente, o que prova que os bloqueios de classe e os bloqueios de objetos são dois bloqueios diferentes, controlando regiões diferentes e elas não interferem entre si. Da mesma forma, enquanto os threads obtêm bloqueios de objetos, eles também podem obter esse tipo de bloqueio, ou seja, eles obtêm dois bloqueios ao mesmo tempo, o que é permitido.
para concluir:
A: estática sincronizada é o escopo de uma determinada classe. O csync estático sincronizado {} impede várias instâncias em vários threads de acessar o método estático sincronizado nesta classe ao mesmo tempo. Funciona em todas as instâncias de objetos de uma classe.
B: Sincronizado é o escopo de uma instância. O ISSYNC () {} sincronizado impede que esta instância acesse o método sincronizado desta classe ao mesmo tempo.
De fato, é muito simples de resumir.
2. A diferença entre o método sincronizado e o código sincronizado rapidamente
Não há diferença entre os métodos sincronizados () {} e sincronizados (this) {}, mas os métodos sincronizados () {} são convenientes para a compreensão da leitura, enquanto sincronizados (this) {} podem controlar com mais precisão as áreas de acesso de conflitos e, às vezes, executar mais eficiente.
Comparação de eficiência entre dois métodos:
1 Sincronizar o bloco, o código é o seguinte:
importar java.util.concurrent.countdownlatch; importar java.util.concurrent.executorService; importar java.util.concurrent.executores; classe pública testsynchronized { / ** * @param args * / public static void main (string [] args) {executService Service = executores.newcachedthreadpool (); Final CountdownLatch CDODORD = new Countdownlatch (1); Final CountdownLatch CDANSWER = new CountdownLatch (3); Final SynchonizedClass SC = new SynchonizedClass (); para (int i = 0; i <3; i ++) {runnable runnable = new runnable () {public void run () {try {CDODORD.AWAIT (); sc.start (); CDANSWER.COUNTDOWN (); } catch (Exceção e) {e.printStackTrace (); }}}; Service.Execute (Runnable); } tente {thread.sleep ((long) (math.random ()*10000)); System.out.println ("thread" + thread.currentThread (). GetName () + "comando de execução de publicação"); CDORD.CountDown (); long begintime = System.currenttimemillis (); System.out.println ("thread" + thread.currentThread (). GetName () + "o comando foi enviado, esperando o resultado"); CDanswer.await (); System.out.println ("thread" + thread.currentThread (). GetName ()) + "Todos os resultados da resposta foram recebidos, o tempo gasto é:" + (system.currenttimemillis ()-iniciar)); } catch (Exceção e) {e.printStackTrace (); } service.shutdown (); }} classe synchonizedclass {public void start () lança interruptedException {thread.sleep (100); // execute outra lógica para consumir o tempo sincronizado (this) {System.out.println ("Eu o executei com 10 ms"); }}} Os resultados da operação são os seguintes:
Principais libera o comando de execução, o thread main enviou o comando, esperando o resultado que eu executei e usei 10 ms
Eu corri usando 10 ms
Eu corri usando 10 ms
O tópico principal recebeu todos os resultados da resposta e o tempo gasto é: 110
O método de sincronização, o código é o seguinte:
importar java.util.concurrent.countdownlatch; importar java.util.concurrent.executorService; importar java.util.concurrent.executores; classe pública testsynchronized { / ** * @param args * / public static void main (string [] args) {executService Service = executores.newcachedthreadpool (); Final CountdownLatch CDODORD = new Countdownlatch (1); Final CountdownLatch CDANSWER = new CountdownLatch (3); Final SynchonizedClass SC = new SynchonizedClass (); para (int i = 0; i <3; i ++) {runnable runnable = new runnable () {public void run () {try {CDODORD.AWAIT (); sc.start (); CDANSWER.COUNTDOWN (); } catch (Exceção e) {e.printStackTrace (); }}}; Service.Execute (Runnable); } tente {thread.sleep ((long) (math.random ()*10000)); System.out.println ("thread" + thread.currentThread (). GetName () + "comando de execução de publicação"); CDORD.CountDown (); long begintime = System.currenttimemillis (); System.out.println ("thread" + thread.currentThread (). GetName () + "o comando foi enviado, esperando o resultado"); CDanswer.await (); System.out.println ("thread" + thread.currentThread (). GetName ()) + "Todos os resultados da resposta foram recebidos, o tempo gasto é:" + (system.currenttimemillis ()-iniciar)); } catch (Exceção e) {e.printStackTrace (); } service.shutdown (); }} classe synchonizedclass {public sincronizado void start () lança interruptedException {thread.sleep (100); // execute outro tempo lógico // sincronizado (this) {System.out.println ("usei 10 ms"); //}}}Os resultados da operação são os seguintes:
Principais libera o comando de execução, o thread main enviou o comando, esperando o resultado que eu executei e usei 10 ms
Eu corri usando 10 ms
Eu corri usando 10 ms
O tópico principal recebeu todos os resultados da resposta e o tempo gasto é: 332
A diferença entre os dois é: 222ms.
A comparação mostra que os blocos de código síncrono são mais eficientes que os métodos de sincronização.
Memória suplementar:
1. Existem dois escopos de palavras -chave sincronizadas:
1) Está dentro de uma instância de objeto. Amethod () {} sincronizado pode impedir que vários threads acessem o método sincronizado desse objeto ao mesmo tempo (se um objeto tiver vários métodos sincronizados, desde que um encadeamento acesse um dos métodos sincronizados, outros threads não podem acessar nenhum método sincronizado no objeto ao mesmo tempo). No momento, o método sincronizado de diferentes instâncias de objetos é ininterrupto. Ou seja, outros threads ainda podem acessar o método sincronizado em outra instância de objeto da mesma classe ao mesmo tempo;
2) É o escopo de uma determinada classe. A astaticmethod estática sincronizada {} impede diferentes objetos de instância (ou o mesmo objeto de instância) em vários threads de acessar o método estático sincronizado nesta classe ao mesmo tempo. Funciona em todas as instâncias de objetos de uma classe.
2. Além de usar a palavra -chave sincronizada antes do método, a palavra -chave sincronizada também pode ser usada em um bloco no método, indicando que apenas acesso mutuamente exclusivo é realizado nos recursos deste bloco. O uso é: sincronizado (this) {/*bloco*/} (ou sincronizado (obj) {/*bloco*/}), e seu escopo é o objeto atual;
3. A palavra -chave sincronizada não pode ser herdada. Ou seja, o método da classe base sincronizado f () {} não é automaticamente sincronizado f () {} na classe herdada, mas se torna f () {}. A classe de herança exige que você especifique explicitamente que um de seus métodos é sincronizado;
Alguma compreensão do sincronizado (isso) (explique bem o trava do objeto, preste atenção à palavra -chave nele)
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.
Adicione um pedaço de código para facilitar o teste de palavras -chave sincronizadas (modificação simples)
classe pública testsynchronized {public void test1 () {sincronizado (this) {int i = 5; while (i--> 0) {System.out.println (thread.currentThread (). getName () + ":" + i); tente {thread.sleep (500); } catch (interruptedException ie) {}}}} public sincronizado void test2 () {int i = 5; while (i--> 0) {System.out.println (thread.currentThread (). getName () + ":" + i); tente {thread.sleep (500); } catch (interruptedException ie) {}}} public sincronizado void test3 () {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 testsynchronized myt2 = new testsynchronized (); TestSynchronized Myt3 = new TestSynchronized (); Thread test1 = new Thread (new runnable () {public void run () {myt2.test2 ();}}, "test1"); Thread test2 = new Thread (novo runnable () {public void run () {myt2.test3 ();}}, "test3"); test1.start () ;; test2.start (); }} Resultados em execução:
Test1: 4Test1: 3Test1: 2Test1: 1Test1: 0Test3: 4Test3: 3Test3: 2Test3: 1Test3: 0
Abaixo, focamos no uso de Sycronized em Java, que é especificamente: o método de sincronização e a palavra -chave sincronizada de bloco 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 da classe, cada classe também corresponde a um bloqueio, para que possamos declarar a função estática do membro da classe como sincronizado estático 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.
Perceber:
Ao usar palavras -chave sincronizadas, você deve evitar o uso de métodos de sono ou rendimento em métodos sincronizados ou blocos sincronizados o máximo possível, porque os blocos de programas sincronizados ocupam bloqueios de objetos; portanto, se você descansar, outros threads só poderão ser executados enquanto aguardam o acordar e terminar de executar. Não apenas afeta seriamente a eficiência, como também não é lógico.
Da mesma forma, não faz sentido chamar o método Yeild no bloco do programa síncrono para desistir do recurso da CPU, porque você ocupa o bloqueio e outros threads mutex ainda não podem acessar o bloco de programa síncrono. Obviamente, os threads que não estão relacionados a blocos de programas síncronos podem obter mais tempo de execução.
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.