Por que a sincronização do thread
Porque quando temos vários threads para acessar uma variável ou objeto ao mesmo tempo, se houver operações de leitura e gravação nesses threads, isso causará confusão no valor variável ou no status do objeto, resultando em exceções do programa. Por exemplo, se uma conta bancária for operada por dois threads ao mesmo tempo, um retira 100 yuan e o outro salva 100 yuan. Supondo que a conta originalmente tivesse 0 yuan, o que aconteceria se o tópico de retirada e o encadeamento de salvamento ocorressem ao mesmo tempo? Se a retirada do dinheiro não for bem -sucedida, o saldo da conta será de 100. Se a retirada do dinheiro for bem -sucedida, o saldo da conta será 0. Então, qual é? É difícil explicar claramente. Portanto, a sincronização com vários threads é resolver esse problema.
1. Código quando está fora de sincronia
Pacote Bank.java Threadtest; out .println (System.currenttimemillis ()+"Save:"+Money); : ::::::::::::::::::::::Here :::::::::::::::::::hee :::::::::::::::::heo the : ::::::::::::::::::::::Here :::::::::::::::::::hee :::::::::::::::::heo the :::::::::::::::::::::::::::::) "Retire:" Money); (String args []) {Final Bank = new B ank (); {Thread.sleep (1000); /n ");}}}); thread tsub = new thread (new runnable () {@Override public void run () {// TODO Auto-Generated Method Stub While (true) {Bank.submoney (100); Banco .Leove (); });
O código é muito simples, não vou explicar. Eu interceptei alguns deles, é muito confuso e não consigo entender a escrita.
Saldo de Balance Insuficiente: 0
Saldo de Balance Insuficiente: 100
1441790503354 Depósito: 100
Saldo de conta: 100
1441790504354 Depósito: 100
Saldo de conta: 100
1441790504354 Retire: 100
Saldo de conta: 100
1441790505355 Depósito: 100
Saldo de conta: 100
1441790505355 retirar: 100
Saldo de conta: 100
2. Use o código síncrono
(1) Método de sincronização:
Existe um método para modificar palavras -chave sincronizadas. Como cada objeto no Java possui um bloqueio embutido, ao modificar o método com essa palavra-chave, o bloqueio embutido protege todo o método. Antes de chamar esse método, você precisa obter um bloqueio embutido, caso contrário, ele estará em um estado de bloqueio.
Bank.java modificado
Vamos dar uma olhada nos resultados em execução:
Saldo de Balance Insuficiente: 0
Saldo de Balance Insuficiente: 0
1441790837380SAVED: 100
Saldo de conta: 100
1441790838380 Retirar: 100
Saldo da conta: 0
1441790838380SAVED: 100
Saldo de conta: 100
1441790839381 removido: 100
Saldo da conta: 0
Eu sinto que isso entende instantaneamente.
Nota: A palavra -chave sincronizada também pode modificar os métodos estáticos.
(2) Sincronizar blocos de código
Ou seja, existe um bloco de declaração modificado pela palavra -chave sincronizada. O bloco de declaração modificado por essa palavra-chave será adicionado automaticamente com um bloqueio embutido para obter sincronização
O código Bank.java é o seguinte:
pacote threadtest; System.out.println (System.CurrentTimMillis ()+"Save:"+Money); .Println ("Balanço insuficiente"); {System.out.println ("Balance de conta:"+contagem);
Os resultados da operação são os seguintes:
Saldo de Balance Insuficiente: 0
1441791806699SAved: 100
Saldo de conta: 100
1441791806700 Retirar: 100
Saldo da conta: 0
1441791807699SAved: 100
Saldo de conta: 100
O efeito é semelhante ao método.
Nota: A sincronização é uma operação de alta sobrecarga, portanto, o conteúdo sincronizado deve ser minimizado. Geralmente, não há necessidade de sincronizar todo o método, basta usar o bloco de código sincronizado para sincronizar o código da chave.
(3) Use variáveis de domínio especiais (voláteis) para obter sincronização de roscas
A. Palavra-chave volátil fornece um mecanismo sem bloqueio para acessar variáveis de domínio
b.
c.
D.Volatile não fornece operações atômicas, nem pode ser usado para modificar variáveis do tipo final
O código Bank.java é o seguinte:
PACOTE THINETEST; (System.currenttimemillis () + "Salvar:" + Money); ; " + contagem);}}
Como é o efeito de operação?
Saldo de Balance Insuficiente: 0
Saldo de Balance Insuficiente: 100
1441792010959SAVED: 100
Saldo de conta: 100
1441792011960 Retirar: 100
Saldo da conta: 0
1441792011961SAVED: 100
Saldo de conta: 100
É porque eu não consigo entender de novo e está confuso de novo? Por que isso? É porque o volátil não pode garantir operações atômicas, portanto, o volátil não pode substituir o sincronizado. Além disso, a Volatile organizará o compilador para otimizar o código; portanto, se você puder usá -lo, ele não se aplica. Seu princípio é que toda vez que um thread deseja acessar uma variável modificada por volátil, é lida da memória, e não no cache; portanto, o valor variável acessado por cada encadeamento é o mesmo. Isso garante sincronização.
(4) Use Lock de reentrada para obter sincronização de roscas
Um novo pacote java.util.Concurrent foi adicionado ao Javase5.0 para suportar a sincronização. A classe Reentrantlock é uma trava reentrante e mutuamente exclusiva que implementa a interface de bloqueio.
Os métodos comuns da classe ReenReAntlock são:
Reentrantlock (): crie uma instância de reentrantlock
Lock (): Obtenha a trava
desbloqueio (): Reentrantlock Nota: ReentrantLock () também possui um construtor que pode criar bloqueios justos, mas não é recomendável usá -lo porque pode reduzir bastante a eficiência de execução do programa.
O código Bank.java é modificado da seguinte forma:
pacote threadtest; //Você precisa declarar este bloqueio privado de bloqueio = novo reentrantlock (); tln (System .CurrentTimMillis () + "Salvar:" + Money); if (contagem - dinheiro <0) {System.out.println ("saldo insuficiente"); } finalmente {Lock.unlock ();
Como é o efeito de operação?
Saldo de Balance Insuficiente: 0
Saldo de Balance Insuficiente: 0
1441792891934 Depósito: 100
Saldo de conta: 100
1441792892935SAVED: 100
Saldo de conta: 200
1441792892954 Retirar: 100
Saldo de conta: 100
O efeito é semelhante aos dois primeiros métodos.
Se a palavra -chave sincronizada puder atender às necessidades dos usuários, use sincronizado porque ela pode simplificar o código. Se você precisar de funções mais avançadas, use a classe Reentrantlock.
(5) Use variáveis locais para obter sincronização de roscas
O código Bank.java é o seguinte:
pacote threadtest; retornar 0; ); ()- dinheiro); Conte.
Efeito de corrida:
Saldo de Balance Insuficiente: 0
Saldo de Balance Insuficiente: 0
1441794247939SAVED: 100
Saldo de conta: 100
Equilíbrio insuficiente
1441794248940SAVE: 100
Saldo da conta: 0
Saldo de conta: 200
Saldo de Balance Insuficiente: 0
1441794249941SAVED: 100
Saldo de conta: 300
Depois de ver o efeito da operação, fiquei confuso no começo. Dê uma olhada no princípio do Threadlocal:
Se você usar o ThreadLocal para gerenciar variáveis, cada thread usando a variável obterá uma cópia da variável e as cópias são independentes uma da outra, para que cada encadeamento possa modificar sua própria cópia da variável à vontade sem afetar outros threads. Agora eu entendo. Portanto, o efeito acima ocorrerá.
Mecanismo de Threadlocal e Sincronização
A. mecanismos de sincronização e de sincronização têm como objetivo resolver o problema de conflito de acesso da mesma variável em multithreads
b.
Agora eu entendo. Cada um tem suas próprias vantagens e desvantagens e tem seus cenários aplicáveis.