Dicas programar: Java Sincronização

Java Sincronização. Linguagem Java.

Sincronização:

* O principio desse capitulo é falar sobre o acesso de múltiplas threads ao mesmo OBJETO, ou seja, 2 chamadas de métodos/instruções em 2 stacks diferentes porem os métodos/instruções são do mesmo objeto.

– QUANDO OCORRE TIMESLICING EM THREADS QUE NÃO ACESSAM OS MESMOS OBJETOS, O PC DO PC REGISTER GARANTE QUE TODAS AS INTRUÇÕES SERÃO FEITAS. NO CASO DE 2 THREADS COM TIMESLICING NO MESMO OBJETO, o pc do PC register garante que todas instruções serão feitas, porem o problema é em qual instrução estamos.

Podemos considera-lá como um átomo, não pode ser dividida.

Descrevendo uma situação provável:

Uma objeto chamado Object, que contem um método chamado somar e outro chamado subtrair, a thread A deve invocar somar e a thread B deve invocar subtrair, porem ambas elas estão FAZENDO NO MESMO OBJETO…Lembre-se muitas vezes o escalonador não tem uma ordem certa com threads de mesma prioridade, Portanto mesmo que você faça primeiro

ThreadA.somar();

ThreadB.subtrair();

Pode ser que ocorra isso: Um timeSlicing de threads, vamos ver:

public int x = 5;

Thread A – Prioridade 5 – Incremente o valor em 5,acessando o método do objeto que praticamente faz isso:

x = x + 5;

Thread B – Prioridade 5 – Decrementa o valor em 5, acessando o método do objeto que praticamente faz isso:

x = x – 5;

Object – as Duas Threads tem o mesmo objeto como RUNNABLE

getfield #2; = Instance variable que é uma referencia dinâmica a constant Pool da classe, que sera resolvida depois…Ou seja instance variable do Objeto

VAMOS VER OQUE ACONTECERÁ:

*Thread A – usa uma parte do TimeSlicing dela, invocando somar() no Object

getfield #2

iconst_5

iadd

putfield #2

Quando o pc do pc register da method area estava na instrução iconst_5 o tempo se esgotou da THREAD A, portanto é hora da THREAD B.(Lembre-se que o mudou porque quando o pc do Pc register faz uma instrução ele salva o estado e guarda o endereço da próxima instrução)

A Operand STACK referente a Thread A esta:

5

5

———x———–

*Thread B – usa uma parte do TimeSlicing dela, invocando subtrair() no Object(Mesmo Objeto que A)

getfield #2

iconst_5

isub

putfield #2

O pc do pc register da method area estava na instrução iconst_5 mudou porque quando o pc do Pc register faz uma instrução ele salva o estado e guarda o endereço da próxima instrução)

A Operand STACK ESTA

5

5

———-x———-

*Thread A usa uma parte do TimeSlicing dela, invocando somar() no Object

getfield #2

iconst_5

iadd

putfield #2

——–>Termino da Frame.

A Operand STACK ESTA – sem nada agora, x = 10 agora.

——–x———-

*Thread B –usa uma parte do TimeSlicing dela, invocando subtrair() no Object(Mesmo Objeto que A)

Repare que, o valor de x é 10, não é mais 5, porem a atualização não acontece aqui, pois a instrução de carregar o valor(getfield #2) foi feita antes da instrução de adicionar(iadd (x = x + 5)) da THREAD A

getfield #2

iconst_5

isub

putfield #2

A Operand STACK esta vazia agora, x = 0; porem deveria ser 5, mais eu sobrescrevi o valor. (E não era essa a intenção)

Conseguiu enxergar a inconsistência de valores? eu simplesmente tinha uma instance variable, com o valor de 5

public int x = 5;

Oque era para acontecer:

Em uma thread eu gostaria de somar + 5…

x = x + 5,

x = 5 + 5;

x = 10;-> Thread A

Em uma outra thread eu gostaria de subtrair 5…

x = x – 5;

x = 10 – 5;

x = 5; – Thread B

Oque aconteceu: x = 0;

No final meu x foi para 0(e era para ser 5), houve uma inconsistência de valores, devido ao fato que temos 2 stacks acessando o mesmo OBJETO supondo que ocorra timeSlicing oque é muito provável e obviou que elas tem a mesma prioridade.

Foi como dito antes, certas coisas são como átomos, não podemos dividir.

Como consertar isso?

Bom sabemos que Garantia de haver ou não Robin-Round(claro e o timeSlicing)não podemos ter, Portanto fazemos o seguinte:

TODO objeto em java tem um cadeado, ESSE CADEADO É DO OBJETO logo esse cadeado pode estar trancado ou destrancado. Só que esse mecanismo só fica ativo quando usamos a keyword synchronized.

Quando um cadeado esta trancado?

Quando uma thread acessa um membo synchronized, ou uma instrução synchronized, A thread se tranca em um “quarto” com o objeto, e diz que só devolve a chave do quarto, QUANDO ELA TERMINAR O SERVIÇO.

E se uma threadB quer usar o Objeto, porem a threadA esta com a chave?

A thread B fica em um Pool CHAMADO: Blocked in Object’s Lock Pool. E so sai de la quando a thread A, sair do quarto e devolver a chave.

SIMPLESMENTE synchronized evita o Robin-Round(claro e o timeSlicing) referente aquele objeto, evita usando o mecanismo de tranca onde a thread fica com a chave,outras threads ate podem acessar o método, so que ficam no Object’s Lock Pool esperando a outra thread sair do “quarto” e devolver a chave.

EXEMPLO DE Método de somar e subtrair synchronized:

Object = é um objeto com uma instance variable (public int x = 5) e 2 métodos sicronizados(somar(), subtrair())

Thread A = é a Thread de SOMA

Thread B = é a thread de subtração

*Thread A entra invoca somar() do objeto Object

getfield #2

iconst_5

iadd

putfield #2

Na instrução iconst_5, terminou o time da thread A, portanto time da Thread B

*Thread B tentar entra invocar subtrair do objeto Object, POREM Não pode, pois não tem a chave para destrancar(Pois subtrair é SINCRONIZADO). PORTANTO THREAD B entra no POOL das Blocked in Object’s Lock Pool.

*Thread A volta da onde tinha parado, e continua o somar() do Object

getfield #2

iconst_5

iadd

putfield #2

agora sim, x = x + 5…x = 10; Thread A terminou o bloco de código do frame , abriu “o quarto” e devolveu a chave.

*Thread B tentar entra invocar subtrair do objeto Object, COMO thread A terminou la esta a chave, B PEGA A CHAVE, se tranca com o objeto “no quarto"e manda a ver no metodo!

getfield #2

iconst_5

isub

putfield #2

AGORA TEMOS O RESULTADO QUE QUERIAMOS, x = 5

TENHO que synchronized o método todo?

Não você pode simplesmente synchronized o código que você quer, especificando um objeto que tem a chave para aquilo.(Eles te dão a chance de ter um bloco onde se consegue garantir o termino coerentemente e onde você pode especificar outro objeto para a obtenção da tranca disso)

public void go(){

synchronized(this){

}

}

Ou declare uma instance variables somente para armazenar a Tranca dele

Object d = new Object();

synchronized(d){

}

Resumo:

– Quando duas threads acessam o mesmo objeto tenha CUIDADO, potenciais problemas podem vir a ocorrer.

– TODO OBJETO TEM UM CADEADO ASSOCIADO COM ELE.

– O cadeado e a chave dele, estão associados ao objeto … A thread simplesmente tranca ele e pega a chave, porem devolve ao OBJETO DEPOIS. Portanto 2 métodos synchronized significa só uma chave para acessar qualquer um dos dois.

– Lembre-se só sincroniza – se membros, e construtor não é considerado membro

– Quando uma thread acessa um membro synchronized do objeto, outras threads não poderão acessar SOMENTE MEMBROS synchronized DESSE OBJETO, ATE QUE A PRIMEIRA THREAD DESTRANQUE…REPITO SOMENTE MEMBROS synchronized QUE ELES NÃO PODERÃO ACESSAR.

Thread safe é estar synchronized.

– O grande problema de não fazer membros thread safe não é a questão de timeslicing mais sim das intruções que já podem ter sido feitas pelo pc do pc Register.

– Podemos fazer métodos (thread safe) ou code_blocks (thread safe), porem em questão de code_blocks é necessário especificar o objeto.

– Se for um membro static, a thread tranca os membros synchronized da classe, e só devolve a chave para a classe quando terminar.

– Quando uma thread A acessa o método/instrução sincronizada de um objeto, e thread B tenta acessar o um método/instrução sincronizada do mesmo objeto, SE thread A ainda não terminou, thread B vai para o estado “Bloqueado em pool de Bloqueio de Objeto” e so sai de la quando a devolver a chave do objeto.

Passo a passo:

1 – thread A entra em um método/instrução sincronizada do objeto1

2 – thread B tenta entrar em algum método/instrução sincronizada do objeto1(mesmo de thread A)

3 –thread B encontra um objeto1 fechado para métodos/instruções sincronizadas e não encontra a chave, thread B vai para o estado: “Bloqueado em pool de bloqueio de objeto”

4 – thread A termina o code_block(ou vai dormir em uma instrução não sincronizada) e libera a chave do objeto1

5 – thread B agora vai para o estado Executável e como só temos essa thread de maior prioridade o escalonador seleciona thread B para ser RUNNING.

Fácil sincronização neh?


Java Download IDE

Baixe os programas e compiladores java.

Java Download Oficial.

NetBeans IDE Download.

Eclipse Downloads.

Oracle Java SE Downloads Netbeans + JDK Bundle .

Java Android Studio.

Java Enide Studio.