Aula prática de Concorrência
Equipe de Monitoria:
Bruno Pereira - bpe
Davi Pires - dpr
Guilherme Barros – gbs2
Thiago Cavalcanti - trc
Roteiro
Motivação
Concorrência em Java
Como podemos criar threads em Java
Formas de sincronização entre threads
Conclusão
Exercícios
Motivação
Concorrência: Executa tarefas de
controle de forma concorrente, onde
diferentes partes do software estão
rodando em paralelo. O paralelismo
pode ser real (quando existem vários
processadores) ou simulado (por
sistemas operacionais tempo real nos
quais as tarefas são escalonadas para
compartilhar o processador)
Concorrência em JAVA
Garbage collection
Interface Gráfica
Objetivo
Mostrar como criar e controlar threads em
uma aplicação Java
Como podemos criar threads
Iremos mostrar como criar threads simples
que imprimem mensagens em um buffer das
duas formas. O primeiro exemplo consiste de
duas classes que são descritas a seguir:
ThreadHeranca: Classe que representa uma
thread criada a partir da herança da classe
java.lang.Thread
Principal: Contem o método main que cria o
buffer e as threads que irão acrescentar
caracteres ao buffer
ThreadHeranca
public class ThreadHeranca extends java.lang.Thread{ private
StringBuffer buf;
private String texto;
public ThreadHeranca(StringBuffer buf, String texto){ this.buf =
buf;
this.texto = texto; }
public void run(){
for(int i=0; i < 10; i++){
buf.append(texto);
try {
sleep((long)(Math.random() * 100));
} catch (InterruptedException ie) { } } } }
Principal
public class Principal{
public static void main(String []args){
StringBuffer buf = new StringBuffer();
ThreadHeranca her1 = new ThreadHeranca(buf, "thread 1\n");
ThreadHeranca her2 = new ThreadHeranca(buf, "thread 2\n");
ThreadHeranca her3 = new ThreadHeranca(buf, "thread 3\n");
her1.start();
her2.start();
her3.start();
for(int i=0; i < Integer.MAX_VALUE/10; i++);
System.out.println(buf.toString());
}
}
Como podemos criar threads
Bem falta agora mostrar a segunda forma de
se criar uma thread em Java: através da
interface java.lang.Runnable. Para isso basta
fazermos pouquíssimas modificações no
exemplo anterior. A classe ThreadInterface
substitui a classe ThreadHeranca.
ThreadInterface
public class ThreadInterface implements Runnable{
private StringBuffer buf;
private String texto;
public ThreadInterface(StringBuffer buf, String texto){
this.buf = buf;
this.texto = texto;
}
public void run(){
for(int i=0; i < 20; i++) {
buf.append(texto);
for(int j=0; j < Integer.MAX_VALUE/600; j++);
}
}
}
Principal2
public class Principal2{
public static void main(String []args){
StringBuffer buf = new StringBuffer();
Thread inter1 = new Thread(new ThreadInterface(buf, "thread 1\n"));
Thread inter2 = new Thread(new ThreadInterface(buf, "thread 2\n"));
Thread inter3 = new Thread(new Threadinterface(buf, "thread 3\n"));
inter1.start();
inter2.start();
inter3.start();
for(int i=0; i < Integer.MAX_VALUE/10; i++);
System.out.println(buf.toString());
}
}
Sincronização
Semáforos
Monitor (synchronized)
Formas de sincronização
Competição – tentam utilizar o mesmo
recurso compartilhado
Cooperação – a comunicação entre as
threads é necessária
Sincronização por competição
Iremos mostrar agora como sincronizar várias
threads que competem por um recurso
compartilhado. A idéia é parecida com o
exemplo anterior aonde várias threads
adicionam
um
String
num
buffer
compartilhado. Ao invés de usarmos um
objeto StringBuffer como buffer, vamos criar
o nosso próprio buffer através da classe
Buffer.java que está descrita abaixo
Buffer.java
public class Buffer{
private StringBuffer buf;
public Buffer(){
buf = new StringBuffer();
}
public synchronized void add(String novo){
for(int i=0; i < novo.length(); i++)
buf.append(novo.charAt(i));
}
public synchronized void print(){
System.out.println(buf);
}
ThreadHeranca2.java
public class ThreadHeranca2 extends Thread{
private Buffer buf;
private String texto;
public ThreadHeranca2(Buffer buf, String texto){
this.buf = buf;
this.texto = texto;
}
public void run(){
for(int i=0; i < 4000; i++)
buf.add(texto);
}
}
Principal3.java
public class Principal3{
public static void main(String []args){
Buffer buf = new Buffer();
ThreadHeranca2 her1 =
ThreadHeranca2 her2 =
ThreadHeranca2 her3 =
ThreadHeranca2 her4 =
ThreadHeranca2 her5 =
ThreadHeranca2 her6 =
...
new ThreadHeranca2(buf, "thread 1\n");
new ThreadHeranca2(buf, "thread 2\n");
new ThreadHeranca2(buf, "thread 3\n");
new ThreadHeranca2(buf, "thread 4\n");
new ThreadHeranca2(buf, "thread 5\n");
new ThreadHeranca2(buf, "thread 6\n");
Principal3.java
her1.start();
her2.start();
her3.start();
her4.start();
her5.start();
her6.start();
for(int i=0; i < Integer.MAX_VALUE/10; i++);
buf.print();
}
}
Um teste simples
Retirem a palavra-chave synchronized
do método add da classe Buffer
E executem!
E ai? Alguma esquisitice? 
Use sabiamente essa palavra!
Sincronização por cooperação
Imagine que a thread principal da aplicação
(aquela que contém o método main) vai
imprimir o conteúdo de um buffer, contudo
ela apenas deve imprimir quando o buffer
estiver cheio. Outras threads ficarão
concorrentemente adicionando caracteres ao
buffer até preenchê-lo. Primeiro vamos ver a
classe Buffer2 que implementa o buffer que
vamos utilizar
Buffer2.java
public class Buffer2{
private char[] buf;
private int tam;
private final int MAX = 100;
public Buffer2(){
buf = new char[MAX];
tam = 0;
}
Buffer2.java
public synchronized void inserir(char c){
if(tam==MAX) notify();
else buf[tam++] = c;
}
public synchronized String esvaziar(){
if(tam < MAX)
try{ wait();
}catch(InterruptedException ie){
}
tam = 0;
return new String(buf);
}
}
ThreadHeranca3.java
ThreadHeranca3.java
public class ThreadHeranca3 extends Thread{
private Buffer2 buf;
private char c;
public ThreadHeranca3(Buffer2 buf, char c){
this.buf = buf;
this.c = c;
}
public void run(){
for(int i=0; i < 1000; i++){
buf.inserir(c);
try {
sleep((long)5);
} catch (InterruptedException ie) {
}
}
}
Principal4.java
public class Principal4{
public static void main(String []args){
Buffer2 buf = new Buffer2();
ThreadHeranca3 her1 = new ThreadHeranca3(buf,'1');
ThreadHeranca3 her2 = new ThreadHeranca3(buf,'2');
ThreadHeranca3 her3 = new ThreadHeranca3(buf,'3');
her1.start();
her2.start();
her3.start();
String result;
for(int i=0; i < 10; i++){
result = buf.esvaziar();
System.out.println("\n\nImpressao # " + (i+1) + ":\n Buffer = " +
result + " -> Tamanho: " + result.length());
}
}
}
Ultimas considerações
wait()
notify()
E as 2 pilhas de JAVA
Ciclo de vida de uma thread
start
Nascimento
Tempo para
adormecer expira
Pronto
notify ou
notifyAll
Inicia E/S
Executando
wait
Esperando
Conclusão de E/S
alocar um
processo
sleep
Adormecido
completo
Morto
Bloqueado
Aula prática de Concorrência
Equipe de Monitoria:
Bruno Pereira - bpe
Davi Pires - dpr
Guilherme Barros – gbs2
Thiago Cavalcanti - trc
Download

Aula prática de Concorrência