Universidade Federal do Amazonas Departamento de Ciência da Computação IEC481 Projeto de Programas Programação Orientada a Objetos em Java Threads Threads Threads Threads Professor: César Melo Slides baseados em materiais preparados pela Profa. Rosiane Freitas e Prof. Horácio
Threads Conceitos Básicos Diversas coisas acontecem simultaneamente: Corpo Humano: Respiração, circulação, digestão Sentidos: visão, olfato, tato, paladar e audição Automóvel: Acelerar, manobrar, ar condicionado, som Computadores também: Compilação, leitura de e-mail, impressão, etc
Threads Conceitos Básicos Ironicamente, dentro de um mesmo processo, há um fluxo seqüencial. Porém, um mesmo programa também pode fazer diversas coisas ao mesmo tempo: como? Threads Linhas de Execução O suporte a múltiplas linhas de execução permite que múltiplos processamentos ocorram em "paralelo" (em computadores com um processador, os threads não são executados em paralelo e, sim, concorrentemente).
Threads Conceitos Básicos Várias threads em várias CPUs Tarefa 1 Tarefa 2 Tarefa 3 Várias threads compartilhand o uma única CPU Tarefa 1 Tarefa 2 Tarefa 3
Threads Conceitos Básicos Queremos escrever programas que possam fazer várias tarefas simultaneamente. baixar uma imagem pela rede. requisitar um relatório atualizado do estoque. rodar várias animações. tudo ao mesmo tempo. Cada thread representa a execução de uma sequência de comandos independentes.
Threads Conceitos Básicos
Threads em Java Suporte a multithreading faz parte da linguagem. Todo programa é executado em pelo menos uma thread. class UmaUnicaThread { // main() é executado em um única thread public static void main(string[] args) { System.out.println(Thread.currentThread()); for (int i=0; i<30; i++) System.out.println("i == " + i);
Threads Exemplo Thread[main,5,main] i == 0 i == 1 i == 2 i == 3 i == 4 i == 5 i == 6 i == 10 i == 20 i == 11 i == 21 i == 12 i == 22... i == 29
Threads Exemplo class CountThread extends Thread { int from, to; public CountThread(int from, int to) { this.from = from; this.to = to; public void run() { for (int i=from; i<to; i++) System.out.println("i == " + i); // Dispara 5 threads, cada uma irá contar 10 vezes public static void main(string[] args) { for (int i=0; i<5; i++) { CountThread t = new CountThread(i*10, (i+1)*10); t.start(); O método run( ) é como se fosse um main( ), só que não é estático
Threads Exemplo class CountThread extends Thread { int from, to; public CountThread(int from, int to) { this.from = from; this.to = to; public void run() { for (int i=from; i<to; i++) System.out.println("i == " + i); // Dispara 5 threads, cada uma irá contar 10 vezes public static void main(string[] args) { for (int i=0; i<5; i++) { CountThread t = new CountThread(i*10, (i+1)*10); t.start(); Iniciar uma thread irá criar uma nova sequência de controle e chamar o método run( ) da thread
Threads Exemplo class CountThread extends Thread { int from, to; public CountThread(int from, int to) { this.from = from; this.to = to; public void run() { for (int i=from; i<to; i++) System.out.println("i == " + i); // Dispara 5 threads, cada uma irá contar 10 vezes public static void main(string[] args) { for (int i=0; i<5; i++) { CountThread t = new CountThread(i*10, (i+1)*10); t.start(); Thread é uma classe em Java!
Threads Exemplo main 0..9 10..19 20.29 30..39 40..49
Threads Exemplo 1a. Execução i == 0 i == 1 i == 2 i == 3 i == 4 i == 5 i == 6 i == 10 i == 20 i == 11 i == 21 i == 12 i == 22... 2a. Execução i == 0 i == 1 i == 2 i == 3 i == 4 i == 10 i == 20 i == 11 i == 21 i == 31 i == 41 i == 5 i == 6... 3a. Execução...
Threads API Thread() Classe Thread possibilita a criação de um objeto executável. void run() invocado pelo sistema de execução da JVM. deve-se sobrescrever este método (polimorfismo por sobreposição) para prover o código a ser executado pela thread. void start() inicia a thread e provoca a chamada de run(). void stop() pára a execução da thread. void suspend() suspende a execução da thread. void resume() retoma a execução interrompida por um suspend().
Threads API static void sleep(long millis) throws InterruptedException põe a thread para dormir por um tempo em milisegundos. void interrupt() interrompe a thread em execução. static boolean interrupted() testa se a thread foi interrompida.
Threads API boolean isalive() testa se a thread está rodando. void setpriority(int p) define a prioridade de execução da thread. void yield() indica ao gerenciador de threads que esta é uma boa hora para rodar outras threads. void join() espera que uma thread termine sua execução.
Threads Estados NEW RUNNABLE NOT RUNNABLE DEAD
Threads Estados Uma thread é finalizada: através dos métodos stop() ou destroy(). ao terminar a execução do método run(). algumas threads podem continuar rodando mesmo após a finalização do run(). se estiver associada a outra thread, terminará juntamente com ela. minhathread.setdeamon(true).
Threads de Usuário x Daemon Uma thread do tipo deamon roda sempre como um pano de fundo da thread que a criou. uma thread deamon termina quando a thread que a criou também terminar. Uma thread que não é uma deamon é chamada de thread de usuário.
Threads de Usuário x Daemon...main(...)... thread1.setdeamon(true); thread1.start(); thread2.setdeamon(true); thread2.start(); thread3.start(); return; Serão automaticamente finalizadas quando o método main( ) for finalizado Pode continuar a execução mesmo após o final de main( )
Sincronização Considere o seguinte código: public class Contador { private int conta = 0; public int incr() { int n = conta; conta = n + 1; return n;
Sincronização O que acontece caso tenhamos duas threads que irão executar o mesmo código a seguir? Ambas as threads estão acessando o mesmo objeto. int cnt = Contador.incr();
Situação 1 Thread 1 Thread 2 conta cnt = Contador.incr(); --- 0 n = conta; --- 0 conta = n + 1; --- 1 return n; --- 1 --- cnt = Contador.incr(); 1 --- n = conta; 1 --- conta = n + 1; 2 --- return n; 2
Situação 2 Thread 1 Thread 2 conta cnt = Contador.incr(); --- 0 n = conta; --- 0 --- cnt = Contador.incr(); 0 --- n = conta; 0 --- conta = n + 1; 1 --- return n; 1 conta = n + 1; --- 1 return n; --- 1
Monitores public class Contador2 { private int conta = 0; public synchronized int incr() { int n = conta; conta = n + 1; return n; Não permite que este método seja executado por mais de uma thread ao mesmo tempo
Monitores Também podemos usar monitores para partes de um método. Indique o recurso synchronized(oobjeto) a ser monitorado sentença; // Sincronizada em relação a oobjeto
Monitores void metodo(umaclasse obj) { synchronized(obj) { obj.variavel = 5; Ninguém poderá usar este objeto enquanto estivermos executando estas operações
Uma Classe Executável As vezes pode não ser conveniente criar uma subclasse de Thread. também não será possível devido ao mecanismo de herança implementado em Java. Solução: Implementar a interface Runnable. A interface Runnable adiciona o método run() sem herdar nada de Thread. public interface Runnable { public void run();
Uma Classe Executável A própria classe Thread implementa a interface Runnable (pacote java.lang), como expresso no cabeçalho da classe: public class Thread extends Object implements Runnable
Uma Classe Executável - Exemplo /* Programa Java que dispara threads */ class CountThreadRun implements Runnable { int from, to; public CountThreadRun(int from, int to) { this.from = from; this.to = to; public void run() { for (int i=from; i<to; i++) System.out.println("i == " + i);
Uma Classe Executável - Exemplo Para executar como uma thread: Cria-se um objeto Thread e associa-se o objeto Runnable com aquela Thread: // Cria uma instância de Runnable Runnable r = new CountThreadRun(10,20); // Cria uma instância de Thread Thread t = new Thread(r); // inicia a execução da thread t.start();
Exemplo Múltipla Impressão /* Este programa cria uma classe chamada MultiplaImpressao*/ public class MultiplaImpressaoThread implements Runnable { Thread threaddaclasse; String string; int contador; int tempodormindo; /* método construtor da classe */ public MultiplaImpressaoThread (String s, int quantasvezes, int dormir) { contador = quantasvezes; string = s; tempodormindo = dormir; threaddaclasse = new Thread (this); threaddaclasse.start(); /* Fim do metodo construtor */
Exemplo Múltipla Impressão public void run () { while (contador > 0) { System.out.println (string); contador ; try { Thread.sleep (tempodormindo); catch (Exception e) { /* Fim while */ /* Fim do metodo run */ public static void main (String args[]) { new MultiplaImpressaoThread ( ping", 5, 300); new MultiplaImpressaoThread ( pong", 5, 500); /* Fim do metodo main */ /* Fim da classe MultiplaImpressaoThread */
Exemplo 2 class MeuApplet extends Applet implements Runnable { private Thread timer = null; public void init() { timer = new Thread(this); timer.start();... public void run() {...
Exemplo Relógio Digital import java.awt.graphics; import java.awt.font; import java.util.date; public class RelogioDigitalThreads extends java.applet.applet implements Runnable { Font afonte = new Font("TimesRoman",Font.BOLD,24); Date adata; Thread runner; public void start() { if (runner == null) { runner = new Thread(this); runner.start(); public void stop() { if (runner!= null) { runner.stop(); runner = null;
Exemplo Relógio Digital public void run() { while (true) { adata = new Date(); repaint(); try { Thread.sleep(1000); catch (InterruptedException e) { public void paint (Graphics g) { g.setfont(afonte); g.drawstring(adata.tostring(),10,50);
Construtores public Thread(); public Thread(Runnable target); public Thread(String name); public Thread(Runnable target, String name); public Thread(ThreadGroup group, Runnable target); public Thread(ThreadGroup group, String name); public Thread(ThreadGroup group, Runnable target, String name);
Escalonamento em Java Mecanismo que determina como os threads executáveis (runnable) irão utilizar tempo de CPU. Preemptiva. filas de prioridades. não há divisão de tempo entre as filas (time sliced). threads com menor prioridade podem ser executadas quando as de maior prioridade não estiverem rodando. sleep(), yield(), stop()
Prioridade Cada thread apresenta uma prioridade de execução. pode ser alterada com setpriority(int p) pode ser lida com getpriority() Algumas constantes incluem: Thread.MIN_PRIORITY Thread.MAX_PRIORITY Thread.NORM_PRIORITY o padrão é Thread.NORM_PRIORITY
Agrupando Threads Pode-se operar as threads como um grupo. pode-se parar ou suspender todas as threads de uma só vez. group.stop(); ThreadGroup g = new ThreadGroup("um grupo de threads");
Agrupando Threads Inclua uma thread em um grupo através do construtor da thread. Thread t = new Thread(g,new ThreadClass(), "Esta thread");
Agrupando Threads Para saber quantas threads em um grupo estão sendo executadas no momento, podemos usar o método activecount(): System.out.println("O número de threads "+ " que podem estar rodando é "+ g.activecount());
Sincronização Considere o seguinte código: public class Contador { private int conta = 0; public int incr() { int n = conta; conta = n + 1; return n;
Sincronização O que acontece caso tenhamos duas threads que irão executar o mesmo código a seguir? Ambas as threads estão acessando o mesmo objeto. int cnt = Contador.incr();
Situação 1 Thread 1 Thread 2 count cnt = Contador.incr(); --- 0 n = conta; --- 0 conta = n + 1; --- 1 return n; --- 1 --- cnt = Contador.incr(); 1 --- n = conta; 1 --- conta = n + 1; 2 --- return n; 2
Situação 2 Thread 1 Thread 2 count cnt = Contador.incr(); --- 0 n = conta; --- 0 --- cnt = Contador.incr(); 0 --- n = conta; 0 --- conta = n + 1; 1 --- return n; 1 conta = n + 1; --- 1 return n; --- 1
Monitores public class Contador2 { private int conta = 0; public synchronized int incr() { int n = conta; conta = n + 1; return n; Não permite que este método seja executado por mais de uma thread ao mesmo tempo
Monitores Também podemos usar monitores para partes de um método. Indique o recurso synchronized(oobjeto) a ser monitorado sentença; // Sincronizada em relação a oobjeto
Monitores void metodo(umaclasse obj) { synchronized(obj) { obj.variavel = 5; Ninguém poderá usar este objeto enquanto estivermos executando estas operações
Threads em Java Dúvidas? Dúvidas