O Mecanismo de Threads em Java 2 Criar uma classe herdeira da super classe Thread public class minhaThread extends Thread{ } Re-escrever o método run( ) public class minhaThread extends Thread{ public void run( ){ ... } } Criar uma classe Teste e criar um objecto public class TesteMinhaThread { minhaThread mt ; mt = new minhaThread(“Apresentação em LP2”) ; } Iniciar a thread implantada public class TesteMinhaThread { minhaThread mt = new minhaThread() ; mt.start( ) ; mt.run( ) ; } Um exemplo: public class minhaThread extends Thread{ private static final int REPETICOES = 10; private static final int ATRASO=1000; private String mensagem; public minhaThread(String msg){ mensagem = msg; } public void run(){ try{ for(int i=1; i<= REPETICOES; i++){ System.out.println( mensagem ); sleep(ATRASO); } } catch(InterruptedException ie){ } } } O resultado seria: um output da mansagem: “Apresentação em LP2” uma vez por segundo, 10 vezes Apresentação em LP2 Apresentação em LP2 Apresentação em LP2 Apresentação em LP2 Apresentação em LP2 Apresentação em LP2 Apresentação em LP2 Apresentação em LP2 Apresentação em LP2 Apresentação em LP2 O interface Runnable Java dispõe de uma interface Runnable O procedimento para criação de objectos é o quase o mesmo: public class MeuRunnable implements Runnable Implementa-se o método run( ) que está declarado na interface Runnable como método abstracto. Quando construímos numa classe teste um objecto do género MeuRunnable os métodos de Thread são invocados com o nome da classe. Por exemplo: Thread.start( ) ; A razão para de ser deste interface tem a ver com a hierarquia. Como Java não implementa a herança múltipla sempre que fosse necessário colocar uma thread a nossa classe teria obrigatoriamente que ser herdeira da classe Thread. O método de classe Thread.start( ) vai executar o método run( ) na classe que implementa a interface Runnable. Agenda de Threads A J.V.M. dispõe de uma agenda para conter as threads, mas… escolhe a thread a executar de uma forma aleatória!! cada thread corre num curto espaço de tempo, chamado de ‘time-slice’ uma thread está à disposição da agenda se não estiver em modo sleep( ) RESUMO: as várias threads que estejam iniciadas - pelo método start( ) – vão ser executadas de forma aleatória Prioridades Podem atribuir-se diferentes prioridades às várias threads através do método setPriority( ) ; Valor (inteiro) 0 Atributo estático Thread.MIN_PRIORITY 5 Thread.NORM_PRIORITY 10 Thread.MAX_PRIORITY (defeito) se for introduzido um valor fora do intervalo 0 – 10 é atirada uma excepção IllegalArgumentException a agenda de threads escolhe sempre para executar a que tiver valor mais elevado se existir mais do que uma thread com a mesma prioridade (mesmo que prioridades elevadas) é escolhida uma aleatoriamente se uma thread com prioridade elevada acorda enquanto outra thread com prioridade inferior está em execução, esta última é suspensa e a thread com maior prioridade é executada. RESUMO: apesar de parecerem bastante úteis, as prioridades não devem ser utilizadas devido à re-utilização de código (uma das características da P.O.O.). Terminar as Threads uma thread termina quando o método run( ) retorna se duas ou mais threads estiverem a resolver o mesmo problema e, se uma encontrar a solução, é necessário notificar as outras para terminarem. Usa-se o método interrupt( ) para se verificar se o estado de uma thread foi alterado pode usar-se o método isInterrupted( ) Na classe MinhaThread por exemplo, o método run( ) podia ter sido escrito da seguinte forma: public void run(){ try{ for( int i=1; i <= REPETICOES && ! isInterrupted( ); i++){ System.out.println( mensagem ); sleep(ATRASO); } } catch(InterruptedException ie){ } } Grupos de Threads No caso de existirem várias threads estas podem ser declaradas como pertencentes a um grupo String nome = “NomeGrupo” ThreadGroup group = new ThreadGroup( nome ) ; As threads sao geridas em sumultâneo. No caso de ser necessário notificar todas para pararem basta escrever: group.interrupt( ) ; Quando um utilizador de uma página web decide que já não quer carregar mais essa página, o programa pode terminar todas as threads em simultâneo. Sincronização Duas ou mais threads podem partilhar o acesso ao mesmo objecto. O acesso partilhado pode provocar um problema que é conhecido como Race Condition. A finalidade do objecto fica depende da thread que vence a competição. Para se resolver esta situação deve-se sincronizar os métodos que alteram o estado de um objecto e que contenham threads. Sincronização de Acesso a um Objecto Deve marcar-se um método com a palavra reservada synchronized. public class NumEncomendas{ public void synchronized AnularEncomenda( ){ … } } Cada objecto tem uma fechadura. Por defeito, esta está “destrancada”. Quando uma thread acciona um método “tranca” a fechadura desta Quando uma outra thread tenta aceder a um método sincronizado tem que aguardar que a thread “destranque” o objecto. Não lhe pode aceder. Duas ou mais threads podem aguardar o “destrancar” de um objecto. A thread que a seguir tem o acesso ao objecto é escolhido conforme a prioridade e, em caso de igualdade de prioridades, é escolhida uma thread aleatoriamente.