Baixe o app para aproveitar ainda mais
Prévia do material em texto
Utilização de Processamento Paralelo CONCEITOS GERAIS DE PARALELISMO E SINCRONIZAÇÃO 1 2 OBJETIVOS: Apresentar os conceitos gerais de Thread e a maneira como é controlado o paralelismo na CPU. Apresentar os estados de uma Thread ao longo de seu ciclo de vida. Identificar problemas de concorrência e metodologias adequadas para sincronização 5 CONCEITOS BÁSICOS: PROCESSO Do ponto de vista do Sistema Operacional, um processo é a ativação de um programa. Um mesmo programa pode dar origem a vários processos. Um exemplo: várias ativações do navegador – esses processos são executados em paralelo. Se a máquina dispõe de mais de um processador, os processos podem ser executados por processadores diferentes. 6 CONCEITOS BÁSICOS: PROCESSOS PARALELOS E PROCESSOS CONCORRENTES Dois processos são ditos paralelos se executam de forma independente ( não compartilham nenhum recurso como um dado em comum, arquivo, interface) Dois processos são ditos concorrentes se estes compartilham algum tipo de recurso. 7 CONCEITOS BÁSICOS CONCORRÊNCIA E PARALELISMO Em uma aplicação: Em muitas situações, linhas de execução paralelas ou concorrentes constituem a forma mais adequada de representar o comportamento da aplicação. Um exemplo: um sistema de controle industrial onde cada máquina tem um padrão de comportamento independente das demais. 8 CONCORRÊNCIA EM JAVA MOTIVAÇÃO Tratamento de eventos assíncronos como aqueles gerados por hardware específico (ex.: interfaces de rede) Desempenho: em máquinas com mais de um processador, a máquina virtual Java pode alocar diferentes linhas de execução em diferentes processadores. Facilidade de programação: em alguns casos, é mais fácil modelar uma aplicação como um conjunto de processos. 9 PROGRAMAÇÃO CONCORRENTE CONCEITOS Thread: Literalmente: “linha” de execução Execução sequencial possui apenas uma “linha” Execução concorrente pode possuir mais de uma “linha” Tarefa Unidade de programa que pode estar em execução concorrente com outras unidades Pode se comunicar com outras tarefas através de variáveis não-locais, compartilhadas, mensagens ou parâmetros Cada tarefa pode originar uma thread 10 THREADS Uma thread é uma linha de execução Em uma thread, uma instrução executa apenas após a outra. 11 MULTI-THREADS É possível “bifurcar” uma thread, criando uma nova linha de execução Múltiplas threads executam em “paralelo” 13 CICLO DE VIDA New Runnable Dead Running Waiting new Thread() start() run() yield() sleep() wait() suspend() quando a thread “acorda” notify()/notifyAll() resume() criação da instância pronta pra execução thread terminada em execução 14 PROGRAMAÇÃO CONCORRENTE 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 15 PROGRAMAÇÃO CONCORRENTE 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. 16 PROGRAMAÇÃO CONCORRENTE MÉTODOS yield(): cede o processamento para outra thread. wait(): utilizado para aguardar até que uma outra thread termine. É uma forma de sincronizar threads. notify() e notifyAll(): utilizados para acordar a thread e verificar as alterações enquanto ela estava em wait(). 17 CONCORRÊNCIA EM JAVA A CLASSE THREAD Define uma “linha de execução”. O método start() dispara a execução de um objeto Thread. O método run() define o comportamento de um objeto Thread durante o seu “tempo de vida”. Pode ser estendida, de forma a atender às necessidades da aplicação: Apenas o método run() precisa ser redefinido 18 EXEMPLO 1 public class MinhaThread extends Thread{ private String nome; private int tempo; public MinhaThread(String nome, int tempo){ this.nome = nome; this.tempo = tempo; start(); } public void run(){ try{ for(int i = 0; i < 6; i++){ System.out.println(nome + " Executando a thread!" + i); Thread.sleep(tempo); } }catch(InterruptedException e){ e.printStackTrace(); } System.out.println(nome + " terminou a execução"); } } 19 EXEMPLO 1 public class Teste { public static void main(String[] args) { MinhaThread thread = new MinhaThread("Tread #1", 600); //thread.start(); MinhaThread thread2 = new MinhaThread("Tread #2", 900); MinhaThread thread3 = new MinhaThread("Tread #3", 500); } } 20 MULTI-THREADS A ideia do multi-threading é simular à ideia de multiprocessamento nos S.O.s modernos Enquanto com processos o SO fica responsável por “paralelizar” a execução Com threads esse trabalho fica por conta de um único processo No caso do Java, por exemplo, é a JVM que gerencia a execução paralela. 21 PROCESSOS VS THREADS Processos podem fazer uso explícito da existência de múltiplos processadores Threads normalmente rodam em um único processo e – portanto – um único processador A bifurcação de uma thread é mais rápida, pois não é necessário repartir todos os recursos do SO Também conhecida como processo leve (lightweight leve) 22 EXEMPLO II Uma aplicação que cria uma instância de uma Thread deve executar o código que vai rodar naquela Thread. Existem duas maneiras de fazer isso: Ele é uma interface por isso não precisamos usar o “start”. Contém somente as assinaturas dos métodos que devem ser implementados; run. O uso da interface Runnable, possibilita a criação de uma thread a partir de uma classe que não é derivada de Thread, dando um grau adicional de liberdade ao projetista. Implementar Runnable: define um único método, run, que contém o código executado na thread. Runnable é passado para o construtor da Thread, como no exemplo a seguir: 23 EXEMPLO II public class MinhaThreadRunnable implements Runnable{ private String nome; private int tempo; public MinhaThreadRunnable(String nome, int tempo){ this.nome = nome; this.tempo = tempo; Thread t = new Thread(this); t.start(); } @Override public void run() { try{ for(int i = 0; i < 6; i++){ System.out.println(nome + " executando a thread " + i); Thread.sleep(tempo); } }catch(InterruptedException ex) { ex.printStackTrace(); } System.out.println("Terminou a executando da thread!"); } } 24 EXEMPLO II public class Teste2 { public static void main(String [] args){ MinhaThreadRunnable thread1 = new MinhaThreadRunnable("#1",900); //Thread t1 = new Thread(thread1); //t1.start(); MinhaThreadRunnable thread2 = new MinhaThreadRunnable("#2",600); MinhaThreadRunnable thread3 = new MinhaThreadRunnable("#3",1100); } } 25 QUAL A MELHOR ABORDAGEM? Quando fazemos extends da Thread, o único método que precisa ser sobreposto é o run Quando implementamos Runnable, também precisamos implementar o método run. Com a classe Runnable, podemos estender qualquer outra classe. Se não for sobrepor qualquer método da classe Thread, pode ser melhor usar a classe Runnable 26 EXEMPLO III Aproveitando a classe MinhaThreadRunnable vamos fazer alguns testes usando isAlive public class Teste3 { public static void main(String [] args){ MinhaThreadRunnable thread1 = new MinhaThreadRunnable("#1",500); MinhaThreadRunnable thread2 = new MinhaThreadRunnable("#2",500); MinhaThreadRunnable thread3 = new MinhaThreadRunnable("#3",500); Thread t1 = new Thread(thread1); Thread t2 = new Thread(thread2); Thread t3 = new Thread(thread3); t1.start(); t2.start(); t3.start(); // usar o isAlive - executa enquanto thread estiver "viva" try{ while(t1.isAlive() || t2.isAlive() || t3.isAlive()){ Thread.sleep(200); } }catch(InterruptedExceptione){ e.printStackTrace(); } System.out.println("Programa encerrado!"); } } #1 executando a thread 0 #2 executando a thread 0 #3 executando a thread 0 #1 executando a thread 1 #2 executando a thread 1 #3 executando a thread 1 #2 executando a thread 2 #1 executando a thread 2 #3 executando a thread 2 #1 executando a thread 3 #2 executando a thread 3 #3 executando a thread 3 #2 executando a thread 4 #1 executando a thread 4 #3 executando a thread 4 #1 executando a thread 5 #2 executando a thread 5 #3 executando a thread 5 Terminou a executando da thread! Terminou a executando da thread! Terminou a executando da thread! Programa encerrado! 27 EXEMPLO IV Aproveitando a classe MinhaThreadRunnable vamos fazer alguns testes usando join public class Teste4 { public static void main(String [] args){ MinhaThreadRunnable thread1 = new MinhaThreadRunnable("#1",500); MinhaThreadRunnable thread2 = new MinhaThreadRunnable("#2",700); MinhaThreadRunnable thread3 = new MinhaThreadRunnable("#3",500); Thread t1 = new Thread(thread1); Thread t2 = new Thread(thread2); Thread t3 = new Thread(thread3); t1.start(); t2.start(); t3.start(); // o join obriga todas as threads serem executadas antes de encerrar try{ t1.join(); t2.join(); t3.join(); }catch(InterruptedException e){ e.printStackTrace(); } System.out.println("Programa encerrado!"); } } #1 executando a thread 0 #2 executando a thread 0 #3 executando a thread 0 #1 executando a thread 1 #3 executando a thread 1 #2 executando a thread 1 #1 executando a thread 2 #3 executando a thread 2 #2 executando a thread 2 #1 executando a thread 3 #3 executando a thread 3 #1 executando a thread 4 #3 executando a thread 4 #2 executando a thread 3 #3 executando a thread 5 #1 executando a thread 5 #2 executando a thread 4 Terminou a executando da thread! Terminou a executando da thread! #2 executando a thread 5 Terminou a executando da thread! Programa encerrado! 28 EXEMPLO V Aproveitando a classe MinhaThreadRunnable vamos definir prioridades public class Teste5 { public static void main(String [] args){ MinhaThreadRunnable thread1 = new MinhaThreadRunnable("#1",500); MinhaThreadRunnable thread2 = new MinhaThreadRunnable("#2",500); MinhaThreadRunnable thread3 = new MinhaThreadRunnable("#3",500); Thread t1 = new Thread(thread1); Thread t2 = new Thread(thread2); Thread t3 = new Thread(thread3); t1.setPriority(5); t2.setPriority(3); t3.setPriority(1); //t1.setPriority(Thread.NORM_PRIORITY); t1.start(); t2.start(); t3.start(); //System.out.println("Programa encerrado!"); } } #1 executando a thread 0 #2 executando a thread 0 #3 executando a thread 0 #3 executando a thread 1 #1 executando a thread 1 #2 executando a thread 1 #1 executando a thread 2 #3 executando a thread 2 #2 executando a thread 2 #1 executando a thread 3 #3 executando a thread 3 #1 executando a thread 4 #3 executando a thread 4 #2 executando a thread 3 #1 executando a thread 5 #3 executando a thread 5 #2 executando a thread 4 #3 - Terminou a executando da thread! #1 - Terminou a executando da thread! #2 executando a thread 5 #2 - Terminou a executando da thread! 29 SINCRONIZAÇÃO é o ato de coordenar as atividades de 2 ou mais threads Motivo: quando 2 ou mais threads precisam acessar um recurso compartilhado, ou somente 1 thread pode acessar o recurso por vez. No Java usamos a palavras chave synchronized em métodos (assinatura) ou um bloco de código 30 EXEMPLO CALCULADORA public class Calculadora { private int soma; public synchronized int somaArray(int[] array){ soma = 0; for (int i = 0; i < array.length; i++){ soma += array[i]; System.out.println("Executando a soma" + Thread.currentThread().getName() + " somando o valor " + array[i] + " com total de " + soma); try{ Thread.sleep(100); }catch(InterruptedException e){ e.printStackTrace(); } } return soma; } } 31 EXEMPLO CALCULADORA public class ThreadSoma implements Runnable{ private String nome; private int[] numeros; private static Calculadora calc = new Calculadora(); public ThreadSoma(String nome, int[] numeros){ this.nome = nome; this.numeros = numeros; new Thread(this, nome).start(); } @Override public void run() { System.out.println(this.nome + " iniciada"); int soma = calc.somaArray(this.numeros); System.out.println("Resultado da soma paa thread " + this.nome + " é " + soma); System.out.println(this.nome + " terminada"); } } 32 EXEMPLO CALCULADORA public class TesteCalculadora { public static void main(String[] args) { int[] array = {1, 2, 3, 4, 5}; ThreadSoma t1 = new ThreadSoma("#1", array); ThreadSoma t2 = new ThreadSoma("#2", array); } } #2 iniciada #1 iniciada Executando a soma#2 somando o valor 1 com total de 1 Executando a soma#2 somando o valor 2 com total de 3 Executando a soma#2 somando o valor 3 com total de 6 Executando a soma#2 somando o valor 4 com total de 10 Executando a soma#2 somando o valor 5 com total de 15 Resultado da soma paa thread #2 é 15 #2 terminada Executando a soma#1 somando o valor 1 com total de 1 Executando a soma#1 somando o valor 2 com total de 3 Executando a soma#1 somando o valor 3 com total de 6 Executando a soma#1 somando o valor 4 com total de 10 Executando a soma#1 somando o valor 5 com total de 15 Resultado da soma paa thread #1 é 15 #1 terminada 33 EXEMPLO Cenário: Uma thread A está sendo executada dentro de um método sincronizado e precisa se acesso a um recurso R que no momento está indisponível Se a thread A ficar esperando por R, irá bloquear o objetos impedindo que outras threads acessem o mesmo Nesse caso a melhor solução para não causar problemas é liberar temporariamente o controle do objeto permitindo que outra thread seja executada. Exemplo: uma caneta para duas pessoas. notify, wait e notifyAll 34 public class TiqueTaque { boolean tique; synchronized void tique(boolean estaExecutando) { if (!estaExecutando) { tique = true; notify(); return; } System.out.print("Tique "); tique = true; notify(); try { while (tique) { wait(); } } catch (InterruptedException e) { e.printStackTrace(); } } synchronized void taque(boolean estaExecutando) { if (!estaExecutando) { tique = false; notify(); return; } System.out.println("Taque"); tique = false; notify(); try { while (!tique) { wait(); } } catch (InterruptedException e) { e.printStackTrace(); } } } 35 public class ThreadTiqueTaque implements Runnable { TiqueTaque tt; Thread t; final int NUM = 5; public ThreadTiqueTaque(String nome, TiqueTaque tt){ this.tt = tt; t = new Thread(this, nome); t.start(); } @Override public void run() { if (t.getName().equalsIgnoreCase("Tique")){ for (int i=0; i<NUM; i++){ tt.tique(true); } tt.tique(false); } else { for (int i=0; i<NUM; i++){ tt.taque(true); } tt.taque(false); } } } 36 public class Teste { public static void main(String[] args) { TiqueTaque tt = new TiqueTaque(); ThreadTiqueTaque tique = new ThreadTiqueTaque("Tique", tt); ThreadTiqueTaque taque = new ThreadTiqueTaque("Taque", tt); try { tique.t.join(); taque.t.join(); } catch (InterruptedException e) { e.printStackTrace(); } } } Tique Taque Tique Taque Tique Taque Tique Taque Tique Taque 37 EXEMPLO Pode ser útil suspender uma thread. Por exemplo, uma thread que mostra a hora do dia. Podemos suspender e posteriormente resumir a execução. Até o Java 2 existiam os métodos suspend, resume e stop O método suspend foi substituído no Java 2 por poder causar problemas de deadlok E como o resume não funciona sem o suspend, também foi removido. O método stop também foi substituído no Java 2 (deve-se usar o método interrupt no lugar) Mas ainda podemos adicionar esses comportamentos na nossa thread de maneira mais segura. suspend, resume e stop 38 public class MinhaThread implements Runnable { private String nome; private boolean estaSuspensa; private boolean foiTerminada; public MinhaThread(String nome) { this.nome = nome; this.estaSuspensa = false; new Thread(this,nome).start(); } @Override public void run() { System.out.println("Executando " + this.nome); try { for (int i = 0; i < 10; i++) { System.out.println("Thread " + nome + ", " + i); Thread.sleep(300); synchronized (this) { while (estaSuspensa) { wait(); } if (this.foiTerminada) { break; } } } } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Thread " + this.nome + " terminada."); } void suspend() { this.estaSuspensa = true; } synchronized void resume() { this.estaSuspensa = false; notify(); } synchronized void stop() { this.foiTerminada = true; notify(); } } 39 public class Teste { public static void main(String[] args) { MinhaThread t1 = new MinhaThread("#1"); MinhaThread t2 = new MinhaThread("#2"); System.out.println("Pausando a Thread #1"); t1.suspend(); try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Pausando a Thread #2"); t2.suspend(); System.out.println("Resumindo a Thread #1"); t1.resume(); try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Resumindo a Thread #2"); t2.resume(); System.out.println("Terminando a Thread #2"); t2.stop(); } } Pausando a Thread #1 Executando #2 Thread #2, 0 Executando #1 Thread #1, 0 Pausando a Thread #2 Resumindo a Thread #1 Thread #1, 1 Resumindo a Thread #2 Terminando a Thread #2 Thread #2, 1 Thread #1, 2 Thread #2 terminada. Thread #1, 3 Thread #1, 4 Thread #1, 5 Thread #1, 6 Thread #1, 7 Thread #1, 8 Thread #1, 9 Thread #1 terminada. 40 THREADS: DEADLOCKS quer usarbloqueia bloqueia 41 public class Deadlock { public static void main(String[] args) { final String RECURSO1 = "Recurso #1"; final String RECURSO2 = "Recurso #2"; Thread t1 = new Thread() { public void run() { synchronized (RECURSO1) { System.out.println("Thread #1: bloqueou recurso 1"); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Thread #1: tendando o acesso ao recurso 2"); synchronized (RECURSO2) { System.out.println("Thread #1: bloqueou recurso 2"); } } } }; // continua 42 // continuando Thread t2 = new Thread() { public void run() { synchronized (RECURSO2) { System.out.println("Thread #2: bloqueou recurso 2"); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Thread #2: tendando o acesso ao recurso 1"); synchronized (RECURSO1) { System.out.println("Thread #2: bloqueou recurso 1"); } } } }; t1.start(); t2.start(); } } Thread #1: bloqueou recurso 1 Thread #2: bloqueou recurso 2 Thread #1: tendando o acesso ao recurso 2 Thread #2: tendando o acesso ao recurso 1 43 ATIVIDADE 04 - SEMÁFORO Já esta disponível no TEAMS. Veja com atenção o enunciado. Esta atividade vale nota e é individual Cuidado com o prazo.
Compartilhar