Programação Concorrente com Thread Java Luiz Affonso Guedes Sistemas Distribuidos Definições Básicas • Threads são sub-procesos no sistema operacional. • É menos custoso gerenciar threads do que processos. • As linguagens Java e Ada possuem funcionalidades MULTITHREADING na própria estrutura da linguagem. • C e C++ necessitam de biblioteca especifica para processamento MULTITHREADING – Posix p_thread Thread em Java • Em Java, threads são implementadas como uma CLASSE – Pacote java.lang.Thread – É uma extensão da classe Thread – Contrutores: • public Thread (String nome_da_thread); • public Thread ( ); // o nome sera Thread-# » Thread-1, Thread-2,… Principais Métodos – run(): é o método que executa as atividades de uma THREAD. Quando este método finaliza, a THREAD também termina. – start(): método que dispara a execução de uma THREAD. Este método chama o método run( ) antes de terminar. – sleep(int x): método que coloca a THREAD para dormir por x milisegundos. Principais Métodos – join( ): método que espera o término da THREAD para qual foi enviada a mensagem para ser liberada. – interrupt( ): método que interrompe a execução de uma THREAD. – interrupted( ): método que testa se uma THREAD está ou não interrompida. Estados de uma Thread em Java Término do tempo de dormida nascimento start( ) notify( ) Fim da E/S pronta notifyAll( ) run( ) Alocar um processador executando wait( ) esperando sleep( ) dormindo Fim do Método run( ) morta E/S bloqueada Prioridade de Thread • Em Java, a prioridade é determinada com um inteiro entre 1 e 10. • A prioridade padrão é o valor 5. • 10 é a maior prioridade e 1 é a menor. • A THREAD herda a prioridade da THREAD que acriou. • void setPriority(int prioridade); • int getPriority( ); Algoritmo de Escalonamento Prioridade 10 Prioridade 9 A B C Prioridade 8 . . . Prioridade 3 D E Prioridade 2 Prioridade 1 G F Exemplo 01 • O programa cria 04 threads e as coloca para dormir. • ThreadBasica é uma extensão da classe Thread. Exemplo 1 – Thread01.java public class Thread01 { // start de execucao das quadro Threads // criacao e start das threads thread1.start(); public static void main( String args[] ) thread2.start(); { thread3.start(); System.out.println("Main: Inicio da Thread main()\n"); thread4.start(); System.err.println( "Main:Threads Basicas iniciadas\n" ); // Declaracao de quatro objetos do tipo ThreadBasica try{ ThreadBasica thread1, thread2, thread3, thread4; thread1.join(); thread2.join(); // criacao de quatro objetos do tipo ThreadBasica thread3.join(); thread1 = new ThreadBasica( "thread1" ); thread4.join(); thread2 = new ThreadBasica( "thread2" ); } thread3 = new ThreadBasica( "thread3" ); catch(InterruptedException x) { } thread4 = new ThreadBasica( "thread4" ); System.out.println("Main: Agora faça o modelo em Rede de Petri desse programa\n"); System.err.println( "\nMain: Disparando as threads" ); thread1.getReferenciaThread(thread2); System.out.println("Main: Fim da Thread main()\n"); } // --- fim do metodo main() } // --------- fim da classe Thread01 ThreadBasica.java // Classe ThreadBsica estende a classe Thread // metodo que ira fazer a execucao da thread public void run() { // escreve que a thread ira dormir try { // Cada objeto desta classe ira dormir aleatoriamente entre 0 e 5 segundos. System.err.println( getName() + " vai comecar a dormir" ); class ThreadBasica extends Thread { //Thread.sleep( tempo_de_sono ); private int tempo_de_sono; sleep(tempo_de_sono); private ThreadBasica namorada = null; //this.sleep(tempo_de_sono); // construtor recebe o nome da thread // ele chama o construtor da classe pai (super) public ThreadBasica( String nome ) { super( nome ); // construtor da classe pai // determina o tempo do sono aleatoriamente entre 0 e 5s tempo_de_sono = (int) ( Math.random() * 5000 ); //metodo estatico da classe Math // escreve o nome da thread e seu tempo de sono System.err.println( "Nome: " + getName() + "; tempo do sono: " + tempo_de_sono ); } void getReferenciaThread(Thread t1) { namorada = (ThreadBasica) t1; } } // tratamento de erro caso haja algum erro durante o processo de sono da thread catch ( InterruptedException interruptedException ) { System.err.println( interruptedException.toString() ); } if(namorada != null) { try{ namorada.join(); } catch(InterruptedException x) { } } // escreve o nome da thread apos o termino de seu sono System.err.println( getName() + " acordou e agora vai morrer" ); }/ } // ----------- fim da classe ThreadBasica Exercício 01 – Analise como se chama o método sleep(). – Crie n THREADs, onde n é definido pelo usuário. – Utilize o método join no main para esperar as THREADs terminarem. • try { uma_thread.join( ); // uma_thread.join(tempo) ...} catch (InterruptedException e) { … } Escalonamento de Threads Prioridade 10 Prioridade 9 A B C Prioridade 8 . . . Prioridade 3 D E Prioridade 2 Prioridade 1 G F Exemplo 02 • Prioridades de Threads • Utilize o método setPriority(int) para mudar a prioridade de threads – Utilize 01 thread com prioridade 1, 01 com prioridade 09 e as outras com prioridade 5. – Faça com que uma das threads de alta prioridade durma por 10 ms antes de terminar. – Faça com que outra thread de alta prioridade faça uma entrada de dado. Exemplo 03 • Problema Produtor X Consumidor - Com buffer de tamanho 1. - Variáveis compartilhadas. - A solução do problema seria utilizar-se duas THREADS: 01 consumidor e 01 produtor. - O que ocorre se não houver sincronização entre a leitura e escrita? UML do Exemplo 03 Thread Principal Consumidor Produtor escrever Buffer ler Exemplo 04 • Problema do Produtor X Consumidor com sincronização do Buffer. • Em Java, a sincronização entre threads é feita através do conceito de monitores. • Monitor é um agrupamento de funções, cujas execuções não podem se dar de forma concorrente. Exemplo 04 • Utilizar os métodos multuamente excludentes de um objeto como do tipo synchronized em Java. • Utilizar os métodos wait( ) e notify( ) para bloquear e liberar, respectivamente, as threads. • Escreva uma classe em Java chamada Semaforo que implente as primitiva P(s) e V(s). Exemplo 5 • Utilização da Classe Semarofo para resolver o problema de ProdutorConsumidor: – Utilizar dois objetos (instâncias) da classe Semaforo. • s1 e s2 • Valores iniciais: s1 = 1; s2 = 0; A interface Runnable • Para utilizar multithreads em Java é necessário instanciar um objeto de uma classe que estende a classe básicaThread, certo? • Uma vez que Java não possui herança múltipla, como eu posso utilizar um objeto, cuja classe já é derivada, como no caso da ClasseThread? – public class Filho extends Pai extends Thread { ………………. } // isto nao eh possivel em Java A interface Runnable • A solução encontrada em Java foi a utilização de uma interface: Runnable – No caso, tem-se de implementar esta interface, que possui o método run( ). – public class Filho extends Pai implements Runnable – Ao implementar uma interface, a classe se capacita a ser tratada como se fosse um objeto do tipo da inteface implementada. • Se a classe Filho implementar a interface Runnable, ela pode ser tratada como tal. A interface Runnable • Cria-se uma thread (Classe Thread), passando para o seu construtor uma referência do objeto que implementa a interface Runnable. – Thread uma_Thread = new Thread(Runnable obj_thread) – Thread uma_Thread = new Thread(Runnable obj_thread, String nome_da_thread) Solução Baseada na Interface Runnable Thread Classe A referência Classe B Runnable Solução Baseada em Herança da Classe Thread Thread Classe B instanciação Exemplo 6 • Classe para exemplificar a utilização da interface Runnable para implementação de Threads.