classMessageLoopextendsThread{StringserverName="127.0.0.1";longid=0;ArrayList<String>myArr=newArrayList<String>();StringrmiName="rmi://"+serverName+"/bullyservice";intkill=0;publicintgetKill(){returnkill;}publicvoidsetKill(intkill){this.kill=kill;}MessageLoop(inti){id=i;}publicvoidrun(){//System.out.println(System.currentTimeMillis());try{bullyc=(bully)Naming.lookup(rmiName);System.out.println("Connecting to: "+rmiName);inquery(c);inth=0;while(h==0&&kill==0){try{.....
O atributo kill deveria ser do tipo boolean (seria mais simples) E DEVERIA SER VOLATILE.
Atributos que forem acessados de Threads diferentes ou devem ser volatiles ou devem sempre ser acessados dentro de blocos synchronized que sincronizem em um mesmo objeto. Por isso que colocar synchronized no getKill() e no setKill() não resolve, pois o atributo ainda é acessado no método run() fora de um bloco synchronized.
O java frequentemente faz caches de objetos específicas para cada Thread. Isso ajuda o programa a ficar mais rápido. No entanto, quando os atributos são acessados de Threads distintas, esse esquema de cache específica para cada Thread acaba criando problemas de visibilidade, aonde cada Thread vê e manipula um valor diferente, o que obviamente acaba por criar bugs muito estranhos e obscuros. O modificador volatile serve exatamente para dizer para a JVM “não faça cache disso aqui”, e assim esse problema se resolve. A outra forma é acessar o atributo SEMPRE de dentro de blocos synchronized, pois a sincronização força a a atualização das caches e garante que apenas uma Thread de cada vez vá manipular aquele atributo de cada vez. No entanto o uso de synchronized é mais pesado do que o de volatile.