Questão 155 testKiller [RESOLVIDO]

bom dia galera, vou postar o código da questão mencionada acima e minha conclusão sobre a mesma, gostaria de saber se estou certo sobre o que acontece nos bastidores e se algo pode se acrescentado pra explicar melhor o código.

segue o texto que publiquei no google+:

algo interessante sobre métodos sincronizados é que apenas uma marcação do método com o modificador não referente a acesso “synchronized” pode não ser suficiente para evitar que 2 threads acessem o mesmo método “ao mesmo tempo”, por exemplo, o código abaixo:

public class Questao155 implements Runnable{

synchronized void hit(long n){
   for (int i = 0; i < 3; i++) {
      System.out.println(n+"-"+ i +" ");
   }
}

public static void main(String[] args) {
   new Thread(new Questao155()).start();
   new Thread(new Questao155()).start();
}

 @Override
  public void run() {
     hit(Thread.currentThread().getId());

   }
}

o problema é que o bloqueio (lock) é feito em this, ou seja as duas threads possuem o bloqueio do método, para solucionar o problema devemos usar um objeto apenas para obter o bloqueio, por exemplo usando um “literal de classe” em um bloco sincronizado em um escopo menor que o do método, exemplo:

void hit(long n){
   synchronized (Questao155.class) {
      for (int i = 0; i < 3; i++) {
         System.out.print(n+"-"+ i +" ");
      }
   }
}

pronto, suas threads serão felizes para sempre e não mais acessarão o método hit simultaneamente, por que quando uma tentar executar o método perceberá que a outra tem o bloqueio do bloco synchronized no objeto Questao155, então ela ficara em algum lugar no pool de execução esperado até que o bloqueio seja liberado.

O bloqueio de metodo deve ser usado quando duas threads acessam o MESMO objeto, como não acontece no seu caso, pois são duas threads com dois objetos diferentes.
Ja o bloqueio no bloco passando a classe ele trava todas as threads em todos os objetos, dae vc vai ver o resultado em seu codigo.

[]'s

obrigado mauricioadl, excelente observação.
Exemplificando o que vc disse (pra ver se entendi) seria como se eu usasse a classe que implementa Runnable e iniciar 2 threads usando a mesma variável de referência certo?!

  Questao155 questao155 = new Questao155();
		new Thread(questao155).start();
		new Thread(questao155).start();

realmente recebo o mesmo resultado como no exemplo com o bloco sincronizado.

[quote=fabiomariner]obrigado mauricioadl, excelente observação.
Exemplificando o que vc disse (pra ver se entendi) seria como se eu usasse a classe que implementa Runnable e iniciar 2 threads usando a mesma variável de referência certo?!

  Questao155 questao155 = new Questao155();
		new Thread(questao155).start();
		new Thread(questao155).start();

realmente recebo o mesmo resultado como no exemplo com o bloco sincronizado.

[/quote]

Exatamente!