Os bloqueios de classe e os bloqueios de objeto entrarão em conflito? Os bloqueios de objetos e os bloqueios privados entrarão em conflito? Ilustração através de exemplos.
1. Acordos Relevantes
Para esclarecer a descrição a seguir, primeiro fazemos as seguintes convenções sobre as definições relevantes de bloqueios envolvidas neste artigo:
1. Bloqueio de classe: adicione bloqueios estáticos e sincronizados aos métodos no código ou segmentos de código sincronizados (xxx.class), como increment() abaixo;
2. Bloqueio de objeto: adicione um bloqueio sincronizado ao método no código, ou um segmento de código sincronizado (este), como synOnMethod() e synInMethod() abaixo;
3. Bloqueio privado: declare uma propriedade privada, como bloqueio de objeto privado dentro da classe, e sincronize (bloqueie) o segmento de código que precisa ser bloqueado, como synMethodWithObj() abaixo.
2. Código de teste
1. Escreva uma classe de inicialização ObjectLock
Copie o código do código da seguinte forma:
classe pública ObjectLock {
public static void main(String[] args) {
System.out.println("hora de início = " + System.currentTimeMillis()+"ms");
Teste LockTestClass = new LockTestClass();
for (int i = 0; i < 3; i++) {
Thread thread = new ObjThread(teste, i);
thread.start();
}
}
}
2. Escreva uma classe de thread ObjThread para iniciar o método de sincronização (observe que seu método de execução pode ser ajustado para diferentes testes)
Copie o código do código da seguinte forma:
classe pública ObjThread estende Thread {
Bloqueio LockTestClass;
int eu = 0;
public ObjThread(LockTestClass lock, int i) {
este.lock = bloqueio;
isto.i = i;
}
execução void pública() {
//Método sem bloqueio
//lock.noSynMethod(this.getId(),this);
//Método de bloqueio de objeto 1, usando synInMethod sincronizado
lock.synInMethod();
//Método de bloqueio de objeto 2, usando o método sincronizado(este)
//lock.synOnMethod();
//Método de bloqueio privado, usando método sincronizado(objeto)
//lock.synMethodWithObj();
//Método de bloqueio de classe, usando método de incremento estático sincronizado
LockTestClass.increment();
}
}
3. Escreva outra classe de teste de bloqueio LockTestClass, incluindo vários métodos de bloqueio
Copie o código do código da seguinte forma:
classe pública LockTestClass {
//Usado para contagem de bloqueios de classe
privado estático int i = 0;
//Bloqueio privado
objeto privado objeto = new Object();
/**
* <p>
* Método sem bloqueio
*
* @param threadID
*@param tópico
*/
public void noSynMethod(threadID longo, thread ObjThread) {
System.out.println("nosyn: classe obj é " + thread + ", threadId é"
+ threadID);
}
/**
* Método de bloqueio de objeto 1
*/
público sincronizado void synOnMethod() {
System.out.println("synOnMethod começa" + ", time = "
+ System.currentTimeMillis() + "ms");
tentar {
Thread.sleep(2000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("synOnMethod termina");
}
/**
* Método de bloqueio de objeto 2, use sincronizado (este) para bloquear
*/
public void synInMethod() {
sincronizado (este) {
System.out.println("synInMethod começa" + ", time = "
+ System.currentTimeMillis() + "ms");
tentar {
Thread.sleep(2000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("synInMethod termina");
}
}
/**
* Método de bloqueio de objeto 3
*/
public void synMethodWithObj() {
sincronizado (objeto) {
System.out.println("synMethodWithObj começa" + ", time = "
+ System.currentTimeMillis() + "ms");
tentar {
Thread.sleep(2000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("synMethodWithObj termina");
}
}
/**
* Bloqueio de classe
*/
incremento de void sincronizado estático público() {
System.out.println("classe sincronizada. i = " + i + ", time = "
+ System.currentTimeMillis() + "ms");
eu++;
tentar {
Thread.sleep(2000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("classe sincronizada termina.");
}
}
3. Resultados do teste
1. Para testar bloqueios de classe e de objeto, modifique o método run de ObjectThread da seguinte forma:
Copie o código do código da seguinte forma:
execução void pública() {
//Método sem bloqueio
//lock.noSynMethod(this.getId(),this);
//Método de bloqueio de objeto 1, usando synInMethod sincronizado
lock.synInMethod();
//Método de bloqueio de objeto 2, usando o método sincronizado(este)
//lock.synOnMethod();
//Método de bloqueio privado, usando método sincronizado(objeto)
//lock.synMethodWithObj();
//Método de bloqueio de classe, usando método de incremento estático sincronizado
LockTestClass.increament();
}
Saída terminal:
Copie o código do código da seguinte forma:
hora de início = 1413101360231ms
synInMethod começa, tempo = 1413101360233ms
synInMethod termina
classe sincronizada. i = 0, tempo = 1413101362233ms.
synInMethod começa, tempo = 1413101362233ms
a classe sincronizada termina.
synInMethod termina
classe sincronizada. i = 1, tempo = 1413101364233ms.
synInMethod começa, tempo = 1413101364233ms
a classe sincronizada termina.
synInMethod termina
classe sincronizada. i = 2, tempo = 1413101366234ms.
a classe sincronizada termina.
Você pode ver que o método de bloqueio de objeto (synInMothod) é 2 segundos mais rápido que o método de bloqueio de classe (incremento) quando é iniciado pela primeira vez. Isso ocorre porque quando synInMehtod é executado, ele dorme por 2 segundos e depois executa o incremento, e esses dois. métodos compartilham o mesmo thread. Portanto, será 2 segundos mais lento. Se o incremento for colocado na frente do synInMethod na execução, o incremento será 2 segundos mais rápido quando for iniciado pela primeira vez.
Quando o método de bloqueio de classe é iniciado, o método de bloqueio de objeto de outro thread também é iniciado quase ao mesmo tempo, indicando que os dois não estão usando o mesmo bloqueio e não haverá competição.
Conclusão: os bloqueios de classe e de objeto não competirão e seus métodos de bloqueio não afetarão um ao outro.
2. Bloqueios privados e bloqueios de objetos, o método run de ObjectThread é modificado da seguinte forma:
Copie o código do código da seguinte forma:
execução void pública() {
//Método sem bloqueio
//lock.noSynMethod(this.getId(),this);
//Método de bloqueio de objeto 1, usando synInMethod sincronizado
lock.synInMethod();
//Método de bloqueio de objeto 2, usando o método sincronizado(este)
//lock.synOnMethod();
//Método de bloqueio privado, usando método sincronizado(objeto)
lock.synMethodWithObj();
//Método de bloqueio de classe, usando método de incremento estático sincronizado
//LockTestClass.increament();
}
Saída terminal:
Copie o código do código da seguinte forma:
hora de início = 1413121912406ms
synInMethod começa, tempo = 1413121912407ms.
synInMethod termina.
synMethodWithObj começa, tempo = 1413121914407ms
synInMethod começa, tempo = 1413121914407ms.
synInMethod termina.
synMethodWithObj termina
synInMethod começa, tempo = 1413121916407ms.
synMethodWithObj começa, tempo = 1413121916407ms
synInMethod termina.
synMethodWithObj termina
synMethodWithObj começa, tempo = 1413121918407ms
synMethodWithObj termina
Muito semelhante aos bloqueios de classe e bloqueios de objetos.
Conclusão: Os bloqueios privados e os bloqueios de objetos não competirão e seus métodos de bloqueio não afetarão um ao outro.
3.Synchronized é adicionado diretamente ao método e sincronizado (este), e o método de execução de ObjectThread é modificado da seguinte forma:
Copie o código do código da seguinte forma:
execução void pública() {
//Método sem bloqueio
//lock.noSynMethod(this.getId(),this);
//Método de bloqueio de objeto 1, usando synInMethod sincronizado
lock.synInMethod();
//Método de bloqueio de objeto 2, usando o método sincronizado(este)
lock.synOnMethod();
//Método de bloqueio privado, usando método sincronizado(objeto)
//lock.synMethodWithObj();
//Método de bloqueio de classe, usando método de incremento estático sincronizado
//LockTestClass.increament();
}
Saída terminal:
Copie o código do código da seguinte forma:
hora de início = 1413102913278ms
synInMethod começa, tempo = 1413102913279ms
synInMethod termina
synInMethod começa, tempo = 1413102915279ms
synInMethod termina
synOnMethod começa, tempo = 1413102917279ms
synOnMethod termina
synInMethod começa, tempo = 1413102919279ms
synInMethod termina
synOnMethod começa, tempo = 1413102921279ms
synOnMethod termina
synOnMethod começa, tempo = 1413102923279ms
synOnMethod termina
Como você pode ver, a saída dos dois é estritamente serial (é claro, se synInMethod ou synOnMethod é executado primeiro quando executado novamente não é determinado, dependendo de quem obtém o bloqueio).
Conclusão: sincronizado adicionado diretamente ao método e sincronizado (este) bloqueiam o objeto atual. Os dois métodos de bloqueio estão em um relacionamento competitivo e apenas um método pode ser executado ao mesmo tempo.