Top Banner
Programação Concorrente em Java Prof. Carlos Bazilio
32

Programação Concorrente em Java - ic.uff.brbazilio/cursos/progpar/Java-Concorrente.pdf · Contém classes utilitárias para programação concorrente Estas classes implementam funcionalidades

Dec 28, 2018

Download

Documents

phungthuan
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Programação Concorrente em Java - ic.uff.brbazilio/cursos/progpar/Java-Concorrente.pdf · Contém classes utilitárias para programação concorrente Estas classes implementam funcionalidades

Programação Concorrente em Java

Prof. Carlos Bazilio

Page 2: Programação Concorrente em Java - ic.uff.brbazilio/cursos/progpar/Java-Concorrente.pdf · Contém classes utilitárias para programação concorrente Estas classes implementam funcionalidades

Criando Threads

● Existem 2 formas básicas de criarmos threads em Java:– Criando uma classe que estende a classe

java.lang.Thread

– Criando uma classe que implementa a interface java.lang.Runnable

Page 3: Programação Concorrente em Java - ic.uff.brbazilio/cursos/progpar/Java-Concorrente.pdf · Contém classes utilitárias para programação concorrente Estas classes implementam funcionalidades

Criando Threadsclass ThinkParallel1 implements Runnable {

...}

class ThinkParallel2 extends Thread {...

}

Thread t = new Thread(new ThinkParallel2());t.start();

Page 4: Programação Concorrente em Java - ic.uff.brbazilio/cursos/progpar/Java-Concorrente.pdf · Contém classes utilitárias para programação concorrente Estas classes implementam funcionalidades

Criando Threads● Em ambas opções devemos dispor um método

chamado run() que inicia a execução da thread● Variáveis podem ser passadas às threads

através do construtor● Membros declarados nas classes são privados

de cada thread

Page 5: Programação Concorrente em Java - ic.uff.brbazilio/cursos/progpar/Java-Concorrente.pdf · Contém classes utilitárias para programação concorrente Estas classes implementam funcionalidades

Criando Threadsclass ThinkParallel1 implements Runnable {

int id;

public ThinkParallel1(int pId) {this.id = pId;

}public void run() {

System.out.println("Thread número: " + id);}

}

Thread t = new Thread(new ThinkParallel1(10));t.start();

Page 6: Programação Concorrente em Java - ic.uff.brbazilio/cursos/progpar/Java-Concorrente.pdf · Contém classes utilitárias para programação concorrente Estas classes implementam funcionalidades

Ciclo de Vida

Nova Thread

Pronto Execução

Bloqueado

Suspenso

Finalizado

start()dispatch

yield/runoutI/OFim I/O Fim da execução

wait()

sleep(long)

notifyAll(),notify() oufim sleep()

Page 7: Programação Concorrente em Java - ic.uff.brbazilio/cursos/progpar/Java-Concorrente.pdf · Contém classes utilitárias para programação concorrente Estas classes implementam funcionalidades

Atomicidade, Sincronização de Memória e termo volatile

● A JVM demanda que leituras e escritas de todos os tipos primitivos (exceto long e double) sejam atômicas– P. ex., teste = true; é sempre atômica

● Além do controle de leitura/escrita, outra questão a ser abordada é a visualização das atualizações

● Em Java esta situação é resolvida declarando o recurso como volatile

Page 8: Programação Concorrente em Java - ic.uff.brbazilio/cursos/progpar/Java-Concorrente.pdf · Contém classes utilitárias para programação concorrente Estas classes implementam funcionalidades

Atomicidade, Sincronização de Memória e termo volatile

● Os tipos long e double têm suporte no pacote java.util.concurrent.atomic

● Por exemplo, temos uma classe AtomicLong para manipulação segura de valores long

Page 9: Programação Concorrente em Java - ic.uff.brbazilio/cursos/progpar/Java-Concorrente.pdf · Contém classes utilitárias para programação concorrente Estas classes implementam funcionalidades

Blocos Síncronos

● Recurso em Java para tratar de situações onde possam ocorrer condição de corrida (race condition)

● Um bloco síncrono sempre está associado a um objeto

● Isto é possível pois todo objeto contém implicitamente um lock

synchronized(object_ref) {...corpo do bloco...

}

Page 10: Programação Concorrente em Java - ic.uff.brbazilio/cursos/progpar/Java-Concorrente.pdf · Contém classes utilitárias para programação concorrente Estas classes implementam funcionalidades

Blocos Síncronosclass ThinkParallel1 implements Runnable {

int id;static int count;public ThinkParallel1(int pId) {

this.id = pId;}public void run() {

System.out.println("Thread número: " + id);synchronized(ThinkParallel1.class){

count++;}

}}

Page 11: Programação Concorrente em Java - ic.uff.brbazilio/cursos/progpar/Java-Concorrente.pdf · Contém classes utilitárias para programação concorrente Estas classes implementam funcionalidades

Blocos Síncronos

● Implementação alternativa poderia utilizar as classes disponíveis no pacote java.util.concurrent.atomic

Page 12: Programação Concorrente em Java - ic.uff.brbazilio/cursos/progpar/Java-Concorrente.pdf · Contém classes utilitárias para programação concorrente Estas classes implementam funcionalidades

Blocos Síncronosclass ThinkParallel1 implements Runnable {

int id;static int count;public ThinkParallel1(int pId) {

this.id = pId;}public void run() {

System.out.println("Thread número: " + id);synchronized(this){ // Erro !!!

count++;}

}}

Page 13: Programação Concorrente em Java - ic.uff.brbazilio/cursos/progpar/Java-Concorrente.pdf · Contém classes utilitárias para programação concorrente Estas classes implementam funcionalidades

public synchronized static void atualiza() {count++;

}// Equivale a ...public static void atualiza() {

synchronized(this){count++;

}}

Blocos Síncronos

● A versão com erro tem o problema de realizar lock às instâncias individualmente

● Uma alternativa para este uso do synchronize é quando um método inteiro deve ser controlado

Page 14: Programação Concorrente em Java - ic.uff.brbazilio/cursos/progpar/Java-Concorrente.pdf · Contém classes utilitárias para programação concorrente Estas classes implementam funcionalidades

wait / notify / notifyAll

● Métodos esperar e sinalizar a disponibilização de um recurso

● São definidos na classe Object● notify e notifyAll só podem ser chamados de

métodos synchronized● Se + de 1 thread está aguardando um recurso,

a escolha da thread a ser acordada é arbitrária● Se não existirem threads aguardando, as

instruções notify são descartadas

Page 15: Programação Concorrente em Java - ic.uff.brbazilio/cursos/progpar/Java-Concorrente.pdf · Contém classes utilitárias para programação concorrente Estas classes implementam funcionalidades

wait / notify / notifyAllExemplo

public class Message { private String msg; public Message(String str){ this.msg=str; } public String getMsg() { return msg; } public void setMsg(String str) { this.msg=str; }}

Page 16: Programação Concorrente em Java - ic.uff.brbazilio/cursos/progpar/Java-Concorrente.pdf · Contém classes utilitárias para programação concorrente Estas classes implementam funcionalidades

wait / notify / notifyAllExemplo

public class Waiter implements Runnable{ private Message msg; public Waiter(Message m){ this.msg=m; } public void run() { String name = Thread.currentThread().getName(); synchronized (msg) { try{ System.out.println(name+" waiting to get notified at time:"+System.currentTimeMillis()); msg.wait(); }catch(InterruptedException e){ e.printStackTrace(); } System.out.println(name+" waiter thread got notified at time:"+System.currentTimeMillis()); //process the message now System.out.println(name+" processed: "+msg.getMsg()); } }}

Page 17: Programação Concorrente em Java - ic.uff.brbazilio/cursos/progpar/Java-Concorrente.pdf · Contém classes utilitárias para programação concorrente Estas classes implementam funcionalidades

wait / notify / notifyAllExemplo

public class Notifier implements Runnable { private Message msg; public Notifier(Message msg) { this.msg = msg; } public void run() { String name = Thread.currentThread().getName(); System.out.println(name+" started"); try { Thread.sleep(1000); synchronized (msg) { msg.setMsg(name+" Notifier work done"); msg.notify(); // msg.notifyAll(); } } catch (InterruptedException e) { e.printStackTrace(); } }}

Page 18: Programação Concorrente em Java - ic.uff.brbazilio/cursos/progpar/Java-Concorrente.pdf · Contém classes utilitárias para programação concorrente Estas classes implementam funcionalidades

wait / notify / notifyAllExemplo

public class WaitNotifyTest { public static void main(String[] args) { Message msg = new Message("process it"); Waiter waiter = new Waiter(msg); new Thread(waiter,"waiter").start(); Waiter waiter1 = new Waiter(msg); new Thread(waiter1, "waiter1").start(); Notifier notifier = new Notifier(msg); new Thread(notifier, "notifier").start(); System.out.println("All the threads are started"); }}

Page 19: Programação Concorrente em Java - ic.uff.brbazilio/cursos/progpar/Java-Concorrente.pdf · Contém classes utilitárias para programação concorrente Estas classes implementam funcionalidades

wait / notify / notifyAllExemplo

waiter waiting to get notified at time:1383760734647waiter1 waiting to get notified at time:1383760734648All the threads are startednotifier startedwaiter waiter thread got notified at time:1383760735649waiter processed: notifier Notifier work done

waiter1 waiting to get notified at time:1383760546239waiter waiting to get notified at time:1383760546241notifier startedAll the threads are startedwaiter waiter thread got notified at time:1383760547241waiter processed: notifier Notifier work donewaiter1 waiter thread got notified at time:1383760547242waiter1 processed: notifier Notifier work done

Page 20: Programação Concorrente em Java - ic.uff.brbazilio/cursos/progpar/Java-Concorrente.pdf · Contém classes utilitárias para programação concorrente Estas classes implementam funcionalidades

Pacote java.util.concurrent

● Contém classes utilitárias para programação concorrente

● Estas classes implementam funcionalidades úteis na programação concorrente, mas difíceis ou tediosas de se programar

● Principais componentes: Executors, Queues, Timing, Synchronizers, Concurrent Collections, Memory Consistency Properties

● http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/package-summary.html

Page 21: Programação Concorrente em Java - ic.uff.brbazilio/cursos/progpar/Java-Concorrente.pdf · Contém classes utilitárias para programação concorrente Estas classes implementam funcionalidades

Executors

● Possuem classes (interfaces e de implementação) voltadas para a gerência de threads

– Pool de threads

– IO assíncrono

– Framework para manipulação de tarefas (tasks)

Page 22: Programação Concorrente em Java - ic.uff.brbazilio/cursos/progpar/Java-Concorrente.pdf · Contém classes utilitárias para programação concorrente Estas classes implementam funcionalidades

Pool de Threadspublic class WorkerThread implements Runnable { private int workerNumber;

WorkerThread(int number) { workerNumber = number; }

public void run() { for (int i=0;i<=100;i+=20) { // Perform some work ... System.out.println("Worker number: " + workerNumber + ", percent complete: " + i ); try { Thread.sleep((int)(Math.random() * 1000)); } catch (InterruptedException e) { } } }}

Page 23: Programação Concorrente em Java - ic.uff.brbazilio/cursos/progpar/Java-Concorrente.pdf · Contém classes utilitárias para programação concorrente Estas classes implementam funcionalidades

Pool de Threadsimport java.util.concurrent.*;

public class ThreadPoolTest { public static void main(String[] args) { int numWorkers = 8; int threadPoolSize = 4; ExecutorService tpes = Executors.newFixedThreadPool(threadPoolSize); WorkerThread[] workers = new WorkerThread[numWorkers]; for (int i = 0; i < numWorkers; i++) { workers[i] = new WorkerThread(i); tpes.execute(workers[i]); } tpes.shutdown(); }}

Page 24: Programação Concorrente em Java - ic.uff.brbazilio/cursos/progpar/Java-Concorrente.pdf · Contém classes utilitárias para programação concorrente Estas classes implementam funcionalidades

Pool de ThreadsExemplo: Crawler para varrer Web

public class Tarefa {String url;int level;

public Tarefa(String url, int level) {this.url = url;this.level = level;

}

public String getUrl() {return url;

}

public int getLevel() {return level;

}}

Page 25: Programação Concorrente em Java - ic.uff.brbazilio/cursos/progpar/Java-Concorrente.pdf · Contém classes utilitárias para programação concorrente Estas classes implementam funcionalidades

Pool de ThreadsExemplo: Crawler para varrer Web

import java.util.concurrent.*;

public class ThreadPoolTest { public static void main(String[] args) { BlockingQueue<Tarefa> urls = new LinkedBlockingQueue<Tarefa>(); urls.add(new Tarefa("http://www.google.com.br", 0)); int threadPoolSize = 16; ExecutorService pool = Executors.newFixedThreadPool(threadPoolSize); Tarefa t = null; WorkerCrawler worker = null; int n_tasks = 0; long tempoLimite = 10L; try {

while ((n_tasks < 100) && ((t = urls.poll(tempoLimite, TimeUnit.SECONDS)) != null)) {worker = new WorkerCrawler(n_tasks, t, urls);pool.execute(worker);n_tasks++;

}} catch (InterruptedException e) {

System.out.println("Interrupção na espera por urls (" + tempoLimite + TimeUnit.SECONDS.name());}

pool.shutdown(); }}

Page 26: Programação Concorrente em Java - ic.uff.brbazilio/cursos/progpar/Java-Concorrente.pdf · Contém classes utilitárias para programação concorrente Estas classes implementam funcionalidades

import java.io.*;import java.net.*;import java.util.concurrent.BlockingQueue;import java.util.regex.*;

public class WorkerCrawler implements Runnable { private int taskNumber; private Tarefa urltoCrawl; BlockingQueue<Tarefa> sharedUrls;

WorkerCrawler(int number, Tarefa t, BlockingQueue<Tarefa> urls) { taskNumber = number; urltoCrawl = t; sharedUrls = urls; }

public void run() { URL url; System.out.println("Thread id: " + Thread.currentThread().getId() + " Task: " + taskNumber + " Nivel: " + urltoCrawl.getLevel() + " Url: " + urltoCrawl.getUrl());

try {url = new URL(urltoCrawl.getUrl());URLConnection conexao = url.openConnection();InputStream stream = conexao.getInputStream();BufferedReader in =

new BufferedReader(new InputStreamReader(stream));

String input = "";String inputLine;while ((inputLine = in.readLine()) != null)

input = input + inputLine;in.close();

// Find links of the form: http://xxx.yyy.zzz String regexp = "http://(\\w+\\.)*(\\w+)"; Pattern pattern = Pattern.compile(regexp); Matcher matcher = pattern.matcher(input);

// find all matches while (matcher.find()) { String match = matcher.group(); sharedUrls.add(new Tarefa(match, urltoCrawl.getLevel() + 1)); }

} catch (MalformedURLException e) {System.out.println("URL mal formada: " + urltoCrawl);

} catch (IOException e) {System.out.println("Erro de entrada/saída na abertura da conexão com

servidor web ou na obtenção dos dados");}

}}

Page 27: Programação Concorrente em Java - ic.uff.brbazilio/cursos/progpar/Java-Concorrente.pdf · Contém classes utilitárias para programação concorrente Estas classes implementam funcionalidades

Queues

● Úteis para manipulação consistente de filas● Destaques:

– ConcurrentLinkedQueue: fila FIFO não-bloqueante e thread-safe

– BlockingQueue: interface para implementação de filas bloqueantes; pode ter capacidade limitada

– BlockingDeque: interface que extende BlockingQueue, permitindo comportamento FIFO e LIFO (pilha)

Page 28: Programação Concorrente em Java - ic.uff.brbazilio/cursos/progpar/Java-Concorrente.pdf · Contém classes utilitárias para programação concorrente Estas classes implementam funcionalidades

Timing

● A classe TimeUnit representa uma unidade de tempo

● É útil por padronizar diferentes operações que possuam timeout

● Há diversos métodos para conversão entre unidades, como toNanos() e toMillis(), para conversão para nanos e milisegundos, respectivamente

Page 29: Programação Concorrente em Java - ic.uff.brbazilio/cursos/progpar/Java-Concorrente.pdf · Contém classes utilitárias para programação concorrente Estas classes implementam funcionalidades

Synchronizers

● 5 classes oferecem ferramentas interessantes para formas de sincronização:

– Semaphore: implementação clássica

– CountDownLatch: implementa bloqueio dado que um número de sinais, eventos e condições ocorram

– CyclicBarrier: ponto de sincronização múltipla

– Phaser: forma mais flexível de barreira para controle de fases em múltiplas threads

– Exchanger: permite 2 threads trocarem objetos num ponto específico da execução

Page 30: Programação Concorrente em Java - ic.uff.brbazilio/cursos/progpar/Java-Concorrente.pdf · Contém classes utilitárias para programação concorrente Estas classes implementam funcionalidades

Concurrent Collections

● Além de Filas, este pacote oferece outras coleções para serem utilizadas em contextos multithreaded:

– ConcurrentHashMap, ConcurrentSkipListMap, ConcurrentSkipListSet, CopyOnWriteArrayList, CopyOnWriteArraySet

● Uma vantagem destas em relação às versões não concorrentes e sincronizadas é escalabilidade, uma vez que as sincronizadas trabalham utilizando lock simples

Page 31: Programação Concorrente em Java - ic.uff.brbazilio/cursos/progpar/Java-Concorrente.pdf · Contém classes utilitárias para programação concorrente Estas classes implementam funcionalidades

ThreadGroup

● Permite o agrupamento lógico de threads● Grupos também podem conter subgrupos

ThreadGroup grupo = new ThreadGroup("Grupo_teste");

...

Thread novathread = new Thread(grupo, "thr1");

Page 32: Programação Concorrente em Java - ic.uff.brbazilio/cursos/progpar/Java-Concorrente.pdf · Contém classes utilitárias para programação concorrente Estas classes implementam funcionalidades

ThreadGroup

● A classe java.lang.ThreadGroup possui alguns métodos para manipulação de grupos

● Dentre esses, podemos citar o método destroy() e o método interrupt()