Neste capítulo, introduziremos palavras -chave sincronizadas. O conteúdo envolvido inclui:
1. Princípio sincronizado
2. Regras básicas sincronizadas
3. Método sincronizado e bloco de código sincronizado
4. Lock de instância e bloqueio global
1. Princípio sincronizado
Em Java, cada objeto possui e possui apenas um bloqueio de sincronização. Isso também significa que o bloqueio de sincronização existe no objeto.
Quando chamamos o método sincronizado de um objeto, adquirimos o bloqueio de sincronização do objeto. Por exemplo, o sincronizado (OBJ) adquire o bloqueio de sincronização do "objet Obj".
O acesso a bloqueios de sincronização por diferentes encadeamentos é mutuamente exclusivo. Em outras palavras, em um determinado momento, a trava de sincronização do objeto só pode ser obtida por um thread! Através de bloqueios de sincronização, podemos obter acesso mutuamente exclusivo a "objetos/métodos" em vários threads. Por exemplo, agora existem dois threads a e threads B, que acessam a "trava síncrona do objeto Obj". Suponha que, em algum momento, o Thread A adquira o "Lock de sincronização do OBJ" e execute algumas operações; B só pode obter o "bloqueio de sincronização do OBJ" até que o Thread a libera a "trava síncrona desse objeto" e só possa ser executada.
2. Regras básicas sincronizadas
Resumimos as regras básicas de sincronizadas nos 3 seguintes e as ilustramos através de exemplos.
Artigo 1: Quando um thread acessa o "método sincronizado" ou "bloco de código sincronizado" de "um determinado objeto", outros threads serão bloqueados do acesso ao "método sincronizado" ou "bloco de código sincronizado" de "o objeto".
Artigo 2: Quando um thread acessa o "método sincronizado" ou "bloco de código sincronizado" de "um determinado objeto", outros threads ainda podem acessar o bloco de código assincronizado de "este objeto".
Artigo 3: Quando um thread acessa o "método sincronizado" ou "bloco de código sincronizado" de "um determinado objeto", outros threads serão impedidos de acessar outros "métodos sincronizados" ou "bloco de código sincronizado" de "o objeto".
Artigo 1
Quando um thread acessa o "método sincronizado" ou "bloco de código sincronizado" de "um determinado objeto", outros threads serão bloqueados do acesso ao "método sincronizado" ou "bloco de código sincronizado" de "o objeto".
Abaixo está o programa de demonstração correspondente ao "bloco de código sincronizado".
A cópia do código é a seguinte:
classe MyRunable implementa Runnable {
@Override
public void run () {
sincronizado (this) {
tentar {
for (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (thread.currentThread (). GetName () + "loop" + i);
}
} catch (interruptedException ie) {
}
}
}
}
classe pública Demo1_1 {
public static void main (string [] args) {
Runnable Demo = New MyRunable ();
Thread T1 = novo Thread (Demo, "T1");
Thread T2 = novo thread (demonstração, "T2");
t1.start ();
t2.start ();
}
}
Resultados em execução:
A cópia do código é a seguinte:
T1 Loop 0
T1 Loop 1
T1 Loop 2
T1 Loop 3
T1 Loop 4
T2 Loop 0
T2 LOOP 1
T2 Loop 2
T2 Loop 3
T2 Loop 4
Resultados Descrição:
Há um "bloco de código sincronizado (este)" no método run (), e T1 e T2 são threads criados com base no objeto "Demo" Runnable. Isso significa que podemos considerar isso em sincronizado (isso) como "objeto de demonstração executável"; Portanto, quando um thread está em execução, outro thread deve aguardar o "Thread em execução" para liberar o "Lock de sincronização de demonstração" antes que possa ser executado.
Se você confirmar, você descobriu esse problema. Em seguida, modificamos o código acima e o executamos para ver como é o resultado e ver se você ficará confuso. O código -fonte modificado é o seguinte:
A cópia do código é a seguinte:
classe Mythread estende thread {
public mythread (nome da string) {
super (nome);
}
@Override
public void run () {
sincronizado (this) {
tentar {
for (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (thread.currentThread (). GetName () + "loop" + i);
}
} catch (interruptedException ie) {
}
}
}
}
classe pública Demo1_2 {
public static void main (string [] args) {
Tópico T1 = novo mythread ("T1");
Tópico T2 = novo mythread ("T2");
t1.start ();
t2.start ();
}
}
Descrição do código:
Comparando Demo1_2 e Demo1_1, descobrimos que a classe Mythread em Demo1_2 é herdada diretamente do Thread, e T1 e T2 são threads infantis mythread.
Felizmente, o método "run () de Demo1_2" também chamado sincronizado (this), assim como o método "run () de Demo1_1" também chamado de sincronizado (isto)!
Então, o processo de execução do Demo1_2 é o mesmo que Demo1_1?
Resultados em execução:
A cópia do código é a seguinte:
T1 Loop 0
T2 Loop 0
T1 Loop 1
T2 LOOP 1
T1 Loop 2
T2 Loop 2
T1 Loop 3
T2 Loop 3
T1 Loop 4
T2 Loop 4
Resultados Descrição:
Se esse resultado não o surpreende, acredito que você tem um entendimento mais profundo de sincronizado e isso. Caso contrário, continue lendo a análise aqui.
Isso em sincronizado (isso) refere -se ao "objeto de classe atual", ou seja, o objeto atual correspondente à classe onde está localizado (este). Seu objetivo é obter a "trava síncrona do objeto atual".
Para Demo1_2, isso em sincronizado (isso) representa o objeto Mythread, enquanto T1 e T2 são dois objetos de mythread diferentes. Para o par Demo1_1, este em sincronizado (isso) representa o objeto inútil;
Artigo 2
Quando um thread acessa o "método sincronizado" ou "bloco de código sincronizado" de "um determinado objeto", outros threads ainda podem acessar o bloco de código assíncronizado de "este objeto".
Abaixo está o programa de demonstração correspondente ao "bloco de código sincronizado".
A cópia do código é a seguinte:
classe Count {
// Método contendo bloco de sincronização sincronizado
public void synMethod () {
sincronizado (this) {
tentar {
for (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (thread.currentThread (). GetName () + "synMethod loop" + i);
}
} catch (interruptedException ie) {
}
}
}
// Método assíncrono
public void NonsynMethod () {
tentar {
for (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (thread.currentThread (). GetName () + "nOnsynMethod loop" + i);
}
} catch (interruptedException ie) {
}
}
}
classe pública Demo2 {
public static void main (string [] args) {
contagem final contagem = new count ();
// Crie um novo T1, T1 chamará o método synMethod () do "objeto de contagem"
Tópico T1 = novo thread (
novo runnable () {
@Override
public void run () {
count.synmethod ();
}
}, "T1");
// Crie um novo T2, T2 chamará o método NonsynMethod () do "objeto de contagem"
Tópico T2 = novo thread (
novo runnable () {
@Override
public void run () {
count.NonsynMethod ();
}
}, "T2");
t1.start ();
t2.start ();
}
}
Resultados em execução:
A cópia do código é a seguinte:
T1 Synmethod Loop 0
T2 NOnsynMethod Loop 0
T1 Synmethod Loop 1
T2 NONSYNMETHOD LOOP 1
T1 Synmethod Loop 2
T2 NOnsynMethod Loop 2
T1 Synmethod Loop 3
T2 NOnsynMethod Loop 3
T1 Synmethod Loop 4
T2 NONSYNMETHOD LOOP 4
Resultados Descrição:
Dois novos threads infantis T1 e T2 são criados no encadeamento principal. T1 chamará o método synMethod () do objeto de contagem, que contém blocos de sincronização; Quando o T1 está em execução, embora sincronizado (isso) seja chamado para obter o "Lock de sincronização da contagem";
Artigo 3
Quando um thread acessa o "método sincronizado" ou "bloco de código sincronizado" de "um determinado objeto", outros encadeamentos acessam a outros "métodos sincronizados" ou "bloco de código sincronizado" de "o objeto" será bloqueado.
Também modificaremos o corpo do método NonsynMethod () no exemplo acima com sincronizado (isso). O código -fonte modificado é o seguinte:
A cópia do código é a seguinte:
classe Count {
// Método contendo bloco de sincronização sincronizado
public void synMethod () {
sincronizado (this) {
tentar {
for (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (thread.currentThread (). GetName () + "synMethod loop" + i);
}
} catch (interruptedException ie) {
}
}
}
// também contém método de bloco de sincronização sincronizado
public void NonsynMethod () {
sincronizado (this) {
tentar {
for (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (thread.currentThread (). GetName () + "nOnsynMethod loop" + i);
}
} catch (interruptedException ie) {
}
}
}
}
classe pública Demo3 {
public static void main (string [] args) {
contagem final contagem = new count ();
// Crie um novo T1, T1 chamará o método synMethod () do "objeto de contagem"
Tópico T1 = novo thread (
novo runnable () {
@Override
public void run () {
count.synmethod ();
}
}, "T1");
// Crie um novo T2, T2 chamará o método NonsynMethod () do "objeto de contagem"
Tópico T2 = novo thread (
novo runnable () {
@Override
public void run () {
count.NonsynMethod ();
}
}, "T2");
t1.start ();
t2.start ();
}
}
(Uma vez) Resultado da execução:
A cópia do código é a seguinte:
synMethod (): 11
synblock (): 3
4. Lock de instância e bloqueio global
Bloqueio de instância-bloqueado em um objeto de instância. Se a aula é um singleton, a fechadura também tem o conceito de uma trava global.
A palavra -chave sincronizada corresponde ao bloqueio da instância.
Bloqueio global- esse bloqueio é direcionado para uma classe.
O bloqueio global corresponde a sincronizado estático (ou bloqueado no objeto de classe ou carregador de classe desta classe).
Há um exemplo muito vívido de "Bloqueio de instância" e "Global Lock":
A cópia do código é a seguinte:
classe Pulbic Something {
public sincronizado void ISSynca () {}
public sincronizado void ISSyncb () {}
public static sincronizado void csynca () {}
public static sincronizado vazio csyncb () {}
}
Suponha que algo tenha duas instâncias x e y. Analise os bloqueios adquiridos pelos quatro conjuntos de expressões a seguir.
(01) x.issynca () e x.issyncb ()
(02) x.issynca () e y.issynca ()
(03) x.csynca () e y.csyncb ()
(04) x.issynca () e algo.csynca ()
(01) não pode ser acessado simultaneamente. Porque ISSynca () e ISSyncb () são bloqueios de sincronização que acessam o mesmo objeto (objeto x)!
A cópia do código é a seguinte:
// Locktest2.Java Código fonte
classe algo {
public sincronizado void ISSynca () {
tentar {
for (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (thread.currentThread (). GetName ()+": iSSynca");
}
} catch (interruptedException ie) {
}
}
public sincronizado void ISSyncb () {
tentar {
for (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (thread.currentThread (). GetName ()+": iSSyncb");
}
} catch (interruptedException ie) {
}
}
public static sincronizado vazio csynca () {
tentar {
for (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (thread.currentThread (). GetName ()+": csynca");
}
} catch (interruptedException ie) {
}
}
public static sincronizado vazio csyncb () {
tentar {
for (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (thread.currentThread (). GetName ()+": csyncb");
}
} catch (interruptedException ie) {
}
}
}
classe pública Locktest2 {
Algo x = novo algo ();
Algo y = novo algo ();
// Compare (02) x.issynca () com y.issynca ()
private void test2 () {
// Crie um novo T21 e T21 ligará para X.issynca ()
Tópico T21 = novo thread (
novo runnable () {
@Override
public void run () {
x.issynca ();
}
}, "T21");
// Crie um novo T22 e T22 ligará para X.issyncb ()
Tópico T22 = novo thread (
novo runnable () {
@Override
public void run () {
y.issynca ();
}
}, "T22");
t21.start ();
t22.start ();
}
public static void main (string [] args) {
Locktest2 Demo = new LockTest2 ();
Demo.test2 ();
}
}
Resultados em execução:
A cópia do código é a seguinte:
T11: ISSynca
T11: ISSynca
T11: ISSynca
T11: ISSynca
T11: ISSynca
T12: ISSYNCB
T12: ISSYNCB
T12: ISSYNCB
T12: ISSYNCB
T12: ISSYNCB
(02) pode ser acessado ao mesmo tempo. Como não está acessando o bloqueio de sincronização do mesmo objeto, x.issynca () acessa a trava de sincronização de x, enquanto y.issynca () acessa a trava de sincronização de y.
A cópia do código é a seguinte:
// Locktest2.Java Código fonte
classe algo {
public sincronizado void ISSynca () {
tentar {
for (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (thread.currentThread (). GetName ()+": iSSynca");
}
} catch (interruptedException ie) {
}
}
public sincronizado void ISSyncb () {
tentar {
for (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (thread.currentThread (). GetName ()+": iSSyncb");
}
} catch (interruptedException ie) {
}
}
public static sincronizado vazio csynca () {
tentar {
for (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (thread.currentThread (). GetName ()+": csynca");
}
} catch (interruptedException ie) {
}
}
public static sincronizado vazio csyncb () {
tentar {
for (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (thread.currentThread (). GetName ()+": csyncb");
}
} catch (interruptedException ie) {
}
}
}
classe pública Locktest2 {
Algo x = novo algo ();
Algo y = novo algo ();
// Compare (02) x.issynca () com y.issynca ()
private void test2 () {
// Crie um novo T21 e T21 ligará para X.issynca ()
Tópico T21 = novo thread (
novo runnable () {
@Override
public void run () {
x.issynca ();
}
}, "T21");
// Crie um novo T22 e T22 ligará para X.issyncb ()
Tópico T22 = novo thread (
novo runnable () {
@Override
public void run () {
y.issynca ();
}
}, "T22");
t21.start ();
t22.start ();
}
public static void main (string [] args) {
Locktest2 Demo = new LockTest2 ();
Demo.test2 ();
}
}
Resultados em execução:
A cópia do código é a seguinte:
T21: ISSynca
T22: ISSynca
T21: ISSynca
T22: ISSynca
T21: ISSynca
T22: ISSynca
T21: ISSynca
T22: ISSynca
T21: ISSynca
T22: ISSynca
(03) não pode ser acessado simultaneamente. Como a csynca () e o csyncb () são tipos estáticos, x.csynca () é equivalente a algo.issynca () e y.csyncb () são equivalentes a algo.issyncb (), eles compartilham um bloqueio de sincronização e não podem ser perguntado ao mesmo tempo.
A cópia do código é a seguinte:
// Locktest3.Java Código fonte
classe algo {
public sincronizado void ISSynca () {
tentar {
for (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (thread.currentThread (). GetName ()+": iSSynca");
}
} catch (interruptedException ie) {
}
}
public sincronizado void ISSyncb () {
tentar {
for (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (thread.currentThread (). GetName ()+": iSSyncb");
}
} catch (interruptedException ie) {
}
}
public static sincronizado vazio csynca () {
tentar {
for (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (thread.currentThread (). GetName ()+": csynca");
}
} catch (interruptedException ie) {
}
}
public static sincronizado vazio csyncb () {
tentar {
for (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (thread.currentThread (). GetName ()+": csyncb");
}
} catch (interruptedException ie) {
}
}
}
classe pública Locktest3 {
Algo x = novo algo ();
Algo y = novo algo ();
// Compare (03) x.csynca () com y.csyncb ()
private void test3 () {
// Crie um novo T31 e T31 ligará para X.issynca ()
Tópico T31 = novo thread (
novo runnable () {
@Override
public void run () {
x.csynca ();
}
}, "T31");
// Crie um novo T32 e T32 chamará x.issyncb ()
Tópico T32 = novo thread (
novo runnable () {
@Override
public void run () {
y.csyncb ();
}
}, "T32");
t31.start ();
t32.start ();
}
public static void main (string [] args) {
LockTest3 Demo = new LockTest3 ();
Demo.test3 ();
}
}
Resultados em execução:
A cópia do código é a seguinte:
T31: Csynca
T31: Csynca
T31: Csynca
T31: Csynca
T31: Csynca
T32: Csyncb
T32: Csyncb
T32: Csyncb
T32: Csyncb
T32: Csyncb
(04) pode ser acessado simultaneamente. Como o ISSYNCA () é um método de instância, o x.issynca () usa o bloqueio do objeto X; Portanto, eles podem ser acessados simultaneamente.
A cópia do código é a seguinte:
// Locktest4.java Código fonte
classe algo {
public sincronizado void ISSynca () {
tentar {
for (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (thread.currentThread (). GetName ()+": iSSynca");
}
} catch (interruptedException ie) {
}
}
public sincronizado void ISSyncb () {
tentar {
for (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (thread.currentThread (). GetName ()+": iSSyncb");
}
} catch (interruptedException ie) {
}
}
public static sincronizado vazio csynca () {
tentar {
for (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (thread.currentThread (). GetName ()+": csynca");
}
} catch (interruptedException ie) {
}
}
public static sincronizado vazio csyncb () {
tentar {
for (int i = 0; i <5; i ++) {
Thread.sleep (100);
System.out.println (thread.currentThread (). GetName ()+": csyncb");
}
} catch (interruptedException ie) {
}
}
}
classe pública Locktest4 {
Algo x = novo algo ();
Algo y = novo algo ();
// compare (04) x.issynca () com algo.csynca ()
private void test4 () {
// Crie um novo T41 e T41 ligará para X.issynca ()
Tópico T41 = novo thread (
novo runnable () {
@Override
public void run () {
x.issynca ();
}
}, "T41");
// Crie um novo T42 e T42 chamará x.issyncb ()
Tópico T42 = novo thread (
novo runnable () {
@Override
public void run () {
Algo.csynca ();
}
}, "T42");
t41.start ();
t42.start ();
}
public static void main (string [] args) {
Locktest4 Demo = new LockTest4 ();
Demo.test4 ();
}
}
Resultados em execução:
A cópia do código é a seguinte:
T41: ISSynca
T42: Csynca
T41: ISSynca
T42: Csynca
T41: ISSynca
T42: Csynca
T41: ISSynca
T42: Csynca
T41: ISSynca
T42: Csynca