Copie o código do código da seguinte forma:
execução nula sincronizada pública()
{
}
Como pode ser visto no código acima, desde que a palavra-chave sincronizada seja adicionada entre void e público, o método run pode ser sincronizado. Ou seja, para a instância do objeto da mesma classe Java, o método run só pode ser sincronizado. chamado por um thread ao mesmo tempo e pode ser chamado por outros threads somente após a execução atual. Mesmo que o thread atual execute o método yield no método run, ele pausa apenas por um tempo. Como outros threads não podem executar o método run, o thread atual eventualmente continuará a execução. Dê uma olhada no seguinte código primeiro:
A palavra-chave sincronizada está vinculada apenas a uma instância de objeto
Copie o código do código da seguinte forma:
teste de classe
{
método void sincronizado público()
{
}
}
classe pública Sync implementa Runnable
{
teste de teste privado;
execução de vazio público ()
{
teste.método();
}
sincronização pública (teste de teste)
{
este.teste = teste;
}
public static void main(String[] args) lança exceção
{
Teste teste1 = novo Teste();
Teste teste2 = novo Teste();
Sincronização sincronização1 = nova sincronização(teste1);
Sincronização sincronização2 = nova sincronização(teste2);
novo Thread(sync1).start();
novo Thread(sync2).start();
}
}
Os métodos de método na classe Test são síncronos. Mas o código acima cria duas instâncias da classe Test, portanto, os métodos de teste1 e test2 são executados separadamente. Para sincronizar os métodos, você deve passar uma instância da mesma classe Test para seu construtor ao criar uma instância da classe Sync, conforme mostrado no código a seguir:
Sincronização sincronização1 = nova sincronização(teste1);
Você não só pode usar sincronizado para sincronizar métodos não estáticos, mas também pode usar sincronizado para sincronizar métodos estáticos. Por exemplo, o método método pode ser definido da seguinte forma:
Copie o código do código da seguinte forma:
teste de classe
{
método público estático sincronizado void() { }
}
Crie uma instância de objeto da classe Test da seguinte maneira:
Teste teste = novo Teste();
Para métodos estáticos, desde que a palavra-chave sincronizada seja adicionada, o método será sincronizado. Quer você use test.method() ou Test.method() para chamar o método, o método é sincronizado e não existe problema com vários. instâncias de métodos não estáticos.
Entre os 23 padrões de design, o modo Singleton também não é seguro para threads se for projetado de acordo com métodos tradicionais. O código a seguir é um modo Singleton não seguro para threads.
Copie o código do código da seguinte forma:
teste de pacote;
// Modo Singleton seguro para threads
classe Singleton
{
amostra Singleton estática privada;
Singleton privado()
{
}
public static Singleton getInstance()
{
if (amostra == nulo)
{
Thread.yield(); // Para amplificar a insegurança do thread no modo Singleton
amostra = novo Singleton();
}
amostra de devolução;
}
}
classe pública MyThread estende Thread
{
execução de vazio público ()
{
Singleton singleton = Singleton.getInstance();
System.out.println(singleton.hashCode());
}
público estático void principal(String[] args)
{
Tópico tópicos[] = new Tópico[5];
for (int i = 0; i < threads.length; i++)
threads[i] = new MeuThread();
for (int i = 0; i < threads.length; i++)
tópicos[i].start();
}
}
O método yield é chamado no código acima para fazer com que a insegurança do thread no modo singleton apareça. Se esta linha for removida, a implementação acima ainda será thread insegura, mas a possibilidade de ocorrência é muito menor.
Os resultados da execução do programa são os seguintes:
Copie o código do código da seguinte forma:
25358555
26399554
7051261
29855319
5383406
Os resultados de execução acima podem ser diferentes em diferentes ambientes de execução, mas geralmente as cinco linhas de saída não serão exatamente iguais. Como pode ser visto nesta saída, existem cinco instâncias de objetos obtidas por meio do método getInstance, e não uma como esperávamos. Isso ocorre porque quando um thread executa Thread.yield(), ele entrega os recursos da CPU para outro thread. Como a instrução para criar uma instância de objeto Singleton não é executada ao alternar entre threads, todos esses threads passam no julgamento if, portanto, cinco instâncias de objeto serão criadas (ou três instâncias de objeto, dependendo de quantos threads passam). o julgamento if antes de criar o objeto Singleton, o resultado poderá ser diferente cada vez que for executado).
Para tornar o modo singleton acima seguro para threads, basta adicionar a palavra-chave sincronizada a getInstance. O código é o seguinte:
público estático sincronizado Singleton getInstance() { }
Claro, existe uma maneira mais simples, que é criar um objeto Singleton ao definir a variável Singleton. O código é o seguinte:
amostra Singleton final estática privada = new Singleton();
Depois é só retornar a amostra diretamente no método getInstance. Embora esse método seja simples, ele não é flexível na criação de um objeto Singleton no método getInstance. Os leitores podem optar por usar métodos diferentes para implementar o padrão singleton de acordo com necessidades específicas.
Há quatro pontos a serem observados ao usar a palavra-chave sincronizada:
1. A palavra-chave sincronizada não pode ser herdada.
Embora você possa usar sincronizado para definir métodos, sincronizado não faz parte da definição do método, portanto a palavra-chave sincronizada não pode ser herdada. Se um método na classe pai usa a palavra-chave sincronizada e substitui esse método na subclasse, o método na subclasse não é sincronizado por padrão e deve ser especificado explicitamente na subclasse. Basta adicionar a palavra-chave sincronizada ao método. Claro, você também pode chamar o método correspondente na classe pai no método da subclasse. Dessa forma, embora o método na subclasse não seja síncrono, a subclasse chama o método de sincronização da classe pai. subclasse é equivalente a sincronização. Os códigos de exemplo para esses dois métodos são os seguintes:
Adicione a palavra-chave sincronizada ao método da subclasse
Copie o código do código da seguinte forma:
classe Pai
{
método void sincronizado público() { }
}
classe Filho estende Pai
{
método void sincronizado público() { }
}
Chame o método sincronizado da classe pai no método da subclasse
Copie o código do código da seguinte forma:
classe Pai
{
método void sincronizado público() { }
}
classe Filho estende Pai
{
método public void() { super.método();
}
2. A palavra-chave sincronizada não pode ser usada ao definir métodos de interface.
3. O construtor não pode usar a palavra-chave sincronizada, mas pode usar o bloco sincronizado a ser discutido na próxima seção para sincronização.
4. sincronizado pode ser colocado livremente.
Nos exemplos anteriores, a palavra-chave sincronizada é colocada antes do tipo de retorno do método. Mas este não é o único lugar onde o sincronizado pode ser colocado. Em métodos não estáticos, sincronizado também pode ser colocado na frente da definição do método. Em métodos estáticos, sincronizado pode ser colocado na frente de estático.
Copie o código do código da seguinte forma:
método void sincronizado público();
método public void sincronizado();
método público estático sincronizado void();
método void estático sincronizado público();
método public static void sincronizado();
Mas observe que sincronizado não pode ser colocado após o tipo de retorno do método. Por exemplo, o código a seguir está errado:
Copie o código do código da seguinte forma:
método sincronizado public void();
método public static void sincronizado();
A palavra-chave sincronizada só pode ser usada para sincronizar métodos, não variáveis de classe. O código a seguir também está errado.
Copie o código do código da seguinte forma:
público sincronizado int n = 0;
público estático sincronizado int n = 0;
Embora o uso do método de sincronização de palavras-chave sincronizadas seja o método de sincronização mais seguro, o uso extensivo da palavra-chave sincronizada causará consumo desnecessário de recursos e perda de desempenho. Embora superficialmente pareça que sincronizado bloqueia um método, na verdade sincronizado bloqueia uma classe. Em outras palavras, se sincronizado for usado ao definir os métodos não estáticos método1 e método2, o método2 não poderá ser executado antes que o método1 seja executado. A situação é semelhante para métodos estáticos e não estáticos. Mas os métodos estáticos e não estáticos não afetam uns aos outros. Dê uma olhada no seguinte código:
Copie o código do código da seguinte forma:
teste de pacote;
classe pública MyThread1 estende Thread
{
public String nome do método;
método público estático void (String s)
{
System.out.println(s);
enquanto (verdadeiro)
}
método void sincronizado público1()
{
método("método método1 não estático");
}
método void sincronizado público2()
{
método("método método2 não estático");
}
método público estático sincronizado void3()
{
método("método estático do método3");
}
método público estático sincronizado void4()
{
método("método estático do método4");
}
execução de vazio público ()
{
tentar
{
getClass().getMethod(nomedométodo).invoke(this);
}
pegar (Exceção e)
{
}
}
public static void main(String[] args) lança exceção
{
MeuThread1 meuThread1 = new MeuThread1();
para (int i = 1; i <= 4; i++)
{
myThread1.methodName = "método" + String.valueOf(i);
novo Thread(meuThread1).start();
dormir(100);
}
}
}
Os resultados da execução são os seguintes:
Copie o código do código da seguinte forma:
Método não estático1 método
Método estático3 método
Como pode ser visto nos resultados de execução acima, o método2 e o método4 não podem ser executados antes que o método1 e o método3 sejam concluídos. Portanto, podemos concluir que se você usar a palavra-chave sincronizada para definir um método não estático em uma classe, isso afetará todos os métodos não estáticos definidos usando a palavra-chave sincronizada nesta classe. Se um método estático for definido, ele afetará todos os métodos estáticos definidos usando a palavra-chave sincronizada na classe. Isso é um pouco como um bloqueio de tabela em uma tabela de dados. Quando um registro é modificado, o sistema bloqueia a tabela inteira. Portanto, o uso extensivo desse método de sincronização reduzirá significativamente o desempenho do programa.