Buscar

Aula 12 - Conceitos Gerais de Paralelismo e Sincronização - Parte 1

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.

Continue navegando