Tecnologias Java Threads Marcio Seiji Oyamada [email protected] Pós-graduação Especialização em Desenvolvimento de Software e Novas Tecnologias
Sep 25, 2015
Tecnologias JavaThreads
Marcio Seiji Oyamada
Especializao em Desenvolvimento de Software e Novas Tecnologias
Contedo programtico
Apresentao da plataforma Java
Threads
Construo de ambientes grficos
Acesso a base de dados
Sockets
RMI
Applets
Linguagem de script (JavaFX)
Threads
nica linha de execuo x mltiplas linhas de execuo
Benefcios
Tempo de resposta
Compartilhamento de recursos
Economia de recursos
Desempenho em arquiteturas multiprocessadas
Muitos para um
Vrias threads no nvel do usurio, mapeadas para uma nica thread no nvel do kernel
Exemplos: Solaris Green Threads
GNU Portable Threads
Um para um
Cada thread no nvel do usurio mapeada para uma thread no nvel do kernel
Exemplos Windows NT/XP/2000
Linux
Solaris 9 e verses posteriores
Threads em Java
Gerenciada pela JVM Mapeamento para o sistema operacional depende
da implementao da JVM
Java Threads Classe Thread ou
Interface Runnable
Interface Runnable
Mtodo necessrio para descrever uma threadpublic interface java.lang.Runnable {
// Methods
public abstract void run();
}
Exemplo:class ThreadInterface implements Runnable{
public void run(){
for (int i=0; i
Classe Thread
Classe principal que representa uma thread em Java
Mtodos para gerenciar threads Obter nome da thread
Alterar a prioridade
Interromper uma thread
Liberar o processador
Criando uma thread com a classe Thread
public class ThreadClasse extends Thread {
public ThreadClasse(){
super();
}
public void run(){
for (int i=0; i
Executando threads (Interface Runnable)
Utilizando a interface Runnablepublic class ExecutaThread {
public static void main(String args[]) throws
InterruptedException{
Thread t1;
Thread t2;
t1= new Thread(new ThreadInterface());
t2= new Thread(new ThreadInterface());
t1.start(); // inicia a execuo da Thread
t2.start(); // inicia a execuo da Thread
System.out.println(Thread inicializadas);
t1.join(); // Aguarda a thread t1 finalizar
t2.join(); // Aguarda a thread t1 finalizar
System.out.println(Thread finalizadas);
}
}
Executando threads (Classe Thread)
Utilizando a Classe Thread
public class ExecutaThread {
public static void main(String[] args) throws
InterruptedException {
// TODO code application logic here
ClasseThread t1= new ClasseThread();
ClasseThread t2= new ClasseThread();
t1.start();
t2.start();
System.out.println("Thread inicializadas");
t1.join();
t2.join();
System.out.println("Thread finalizadas");
}
}
Executors
Gerencia um conjunto de Threads FixedThreadPool: nmero fixo de threads
CachedThreadPool: aloca dinamicamente
FixedThreadPool Evita o overhead com a criao de thread
Maior controle dos recursos utilizados durante a execuo do sistema
Exemplo Executors (1)import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Main {
public static void main(String[] args) {
// TODO code application logic here
ExecutorService executor=
Executors.newCachedThreadPool();
for (int i=0; i < 5; i++){
executor.execute(new ThreadInterface());
}
System.out.println("Threads executando");
executor.shutdown();
}
}
Exemplo: Executors (2)
public class ThreadInterface implements Runnable{
public void run() {
for (int i=0; i
Executors
Mtodos Execute(Interface Runnable): submete uma nova
interface para ser executada
Shutdown(): previne que outras threads sejam submetidas ao ExecutorService
ShutdownNow(): tentar finalizar a execuo das Threads
Interrompendo Threadspublic class MainInterruptTest {
public static void main(String[] args) throws InterruptedException {
ExecutorService executor= Executors.newCachedThreadPool();
for (int i=0; i < 10; i++)
executor.execute(new MyThread());
System.out.println("Sleeping....");
TimeUnit.SECONDS.sleep(10);
executor.shutdownNow();
System.out.println("Shutdown solicitado");
}
}
class MyThread implements Runnable{
public void run() {
boolean sair=false;
while (!sair){
System.out.println(Thread.currentThread().getName());
if (Thread.currentThread().isInterrupted()){
System.out.println("Interrupo solicitada, finalizando a
Thread"+ Thread.currentThread().getName());
sair= true;
}
}
}
}
Thread.yield()
Para a execuo da Thread atual e libera o processador para que uma outra Thread possa executar Forar a troca de contexto e conseqentemente uma melhor
distribuio do processador
public class ThreadInterface implements Runnable{
public void run() {
for (int i=0; i
Threads:Sleeppublic class SleepingTest implements Runnable {
public void run() {
try {
for (int i=0; i
Inicializao de atributospublic class SleepingTest implements Runnable{
boolean setYield= false;
public SleepingTest (boolean _setYield){
this.setYield= _setYield;
}
public void run() {
for (int i=0; i
Exerccios
1) Qual o comportamento na execuo das Threads utilizando o mtodo yield()?
2) Faa uma aplicao multithread onde cada Thread escreva na tela N vezes uma String. O valor N e a String sero passados como parmetro pelo construtor
Threads: Retornando valores
A interface Runnable no define um mtodo para retornar valores Soluo 1: utilizar a interface Callable
Soluo 2: retornar os valores em um objeto compartilhado
Problemas de sincronizao em dados compartilhados (veremos mais adiante)
Adotemos a soluo 1...
Interface Callable
Callable: generic possibilitando definir o tipo de retorno
Mtodo call: ponto de entrada para a Thread (ao invs do mtodo run()), retornando o tipo definido no generic Callable
Exemplo: Callable(1)
public class ThreadCallable implements
Callable{
private static Random generator= new Random();
public int call(){
return generator.nextInt(1000);
}
}
Exemplo: Callable(2)import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.ArrayList;
public class MainCallable {
public static void main(String[] args) {
ExecutorService executor= Executors.newCachedThreadPool();
ArrayList resultados= new ArrayList();
for (int i=0; i < 10; i++)
resultados.add(executor.submit(new ThreadCallable()));
executor.shutdown();
for (int i=0; i< resultados.size(); i++){
try {
Future result;
result = resultados.get(i);
System.out.println(result.get());
} catch (InterruptedException ex) {
ex.printStackTrace();
} catch (ExecutionException ex) {
ex.printStackTrace();
}
}
}
}
Exerccio
Faa uma aplicao Java multithread para buscar um dado elemento em um vetor (desordenado). Utilize um objeto Random para gerar numeros aleatrios Cada Thread ficar responsvel pela busca em uma
parte do vetor
Retorne a posio do elemento no vetor ou 1 caso o elemento no foi encontrado
ThreadFactory
Um Executor utiliza padro de projeto Factory para criar as Threads
O desenvolvedor pode criar sua prpria ThreadFactory para criar threads Definir atributos especficos
Definir prioridades durante a criao de threads
Definir manipuladores de exceo
ThreadFactory(1)import java.util.concurrent.*;
public class MyThreadFactory implements ThreadFactory{
private static int count;
public MyThreadFactory(){
count=0;
}
public Thread newThread(Runnable r) {
Thread t= null;
t = new Thread(r);
count++;
t.setName("MinhaThread[" + count + "]");
return t;
}
}
ThreadFactory(2)Classe MyThread
public class MyThread implements Runnable {
public void run() {
System.out.print(Thread.currentThread().getName());
System.out.println(Thread.currentThread().getId());
}
}
----
Classe principal
import java.util.concurrent.*;
public class MainTreadFactory {
public static void main(String[] args) {
ExecutorService executor=Executors.newFixedThreadPool(10, new MyThreadFactory());
for (int i=0; i < 10; i++)
executor.execute(new MyThread());
executor.shutdown();
}
}
Exerccio
No exerccio anterior, foi utilizado um gerenciador de Threads com nmero fixo. Substitua por um gerenciador dinmico (Executors.newCachedThreadPool(new MyFactoryThread()) Existe alguma diferena na sada gerada?
Tratando exceptionimport java.util.concurrent.*;
public class ExceptionThread implements Runnable {
public void run() {
throw new RuntimeException();
}
public static void main(String [] args) {
ExecutorService exec = Executors.newCachedThreadPool() ;
exec.execute(new ExceptionThread());
exec.shutdown();
}
}
Tratando internamenteimport java.util.concurrent.*;
public class ExceptionThread implements Runnable {
public void run() {
try {
throw new RuntimeException();
catch (Exception ex){
ex.printStackTrace();
}
}
public static void main(String [] args) {
ExecutorService exec = Executors.newCachedThreadPool() ;
exec.execute(new ExceptionThread());
exec.shutdown();
}
}
Tratando exception(2)/ / : concurrency/NaiveExceptionHandling.java
import java.util.concurrent.*;
public class NaiveExceptionHandling {
public static void main(String[] args) {
try {
ExecutorService exec= Executors.newCachedThreadPool();
exec.execute(new ExceptionThread()) ;
exec.shutdown();
} catch(RuntimeException ue) {
// Esse cdigo no executar!!
System.out.println("Exception has been handled!");
}
}
}
Registrando um tratador de excees
Como pegar excees que no so tratadas internamente nas Threads?
Registrar um tratador de excees durante a criao de uma thread (ThreadFactory) Interface Thread.UncaughtExceptionHandler
public void uncaughtException(Thread t,Throwable e)
Tratador de excees(1)public class MyThreadFactory implements ThreadFactory{
public Thread newThread(Runnable arg0) {
Thread t=new Thread(arg0);
t.setUncaughtExceptionHandler(new TrataException());
return t;
}
}
class TrataException implements UncaughtExceptionHandler{
public void uncaughtException(Thread arg0, Throwable arg1) {
System.out.println("Tratador da exceo da Thread");
}
}
Tratador de excees(2)class MyThread implements Runnable{
public void run(){
throw new RuntimeException();
}
}
public class MainUncaughtException {
public static void main(String[] args) {
ExecutorService executor= Executors.newCachedThreadPool(new
MyThreadFactory());
for (int i=0; i < 5 ; i++)
executor.execute(new MyThread());
}
}
Sincronizao entre threads
Acesso a variveis compartilhadas
Sincronizao
Programa concorrente Executado por diversos processos
Acesso concorrente a dados
Paralelismo real x Paralelismo aparente Multiprocessadores: paralelismo real
Paralelismo aparente: concorrncia
Programas concorrentes
Processos seqenciais que executam concorrentemente (afetam ou so afetados por outros programas)
Motivao Aumento de desempenho em mquinas
multiprocessadas
Interface com o usurio
Sobreposio de operaes de E/S e processamento
Problema produtor-consumidor
Seja um buffer compartilhado entre dois processos/threads. O processo produtor coloca dados em um buffer que so retirados pelo processo consumidor
Possvel implementao Uma varivel count armazena o nmero de posies
preenchidas no buffer Inicialmente armazena o valor 0 Quando o processo produtor coloca um dado no buffer,
count incrementado Quando o processo consumidor retira o dado do buffer,
count decrementado
Produtor
while (true) {
/* produce an item and put in nextProduced */
while (count == BUFFER_SIZE)
; // do nothing
buffer [in] = nextProduced;
in = (in + 1) % BUFFER_SIZE;
count++;
}
Consumidor
while (true) {
while (count == 0)
; // do nothing
nextConsumed = buffer[out];
out = (out + 1) % BUFFER_SIZE;
count--;
/* consume the item in nextConsumed
}
Condio de corrida
count++ ou count register= count
register= count+1
count= register Considere a execuo intercalada com count = 5
inicialmente:S0: produtor executa register1 = count {register1 = 5}S1: produtor executa register1 = register1 + 1 {register1 = 6} S2: consumidor executa register2 = count {register2 = 5} S3: consumidor executa register2 = register2 - 1 {register2 = 4} S4: produtor executa count = register1 {count = 6 } S5: consumidor executa count = register2 {count = 4}
Problema da seo crtica
Condio de corrida: vrios processos/threadmanipulam conjuntos de dados onde o resultado depende da ordem de execuo
Seo crtica: trecho de cdigo onde somente um processo pode executar por vez
Soluo
Criar um protocolo que garanta a excluso mtua Execuo da seo crtica por somente um
processo/thread
Propriedades da seo crtica
Regra 1: Excluso mtua Regra 2: Progresso
Nenhum processo fora da seo crtica pode bloquear um outro processo
Regra 3: Espera limitada Nenhum processo pode esperar infinitamente para
entrar na seo crtica
Regra 4 Nenhuma considerao sobre o nmero de
processadores ou velocidades relativas
Acesso concorrente a dados
Classe Contapublic class Conta {
int saldoPoupanca;
int saldoCC;
public Conta(int _saldoPoupanca, int _saldoCC){
saldoPoupanca= _saldoPoupanca;
saldoCC= _saldoCC;
}
public void transferePoupanca(int v){
saldoCC -= v;
saldoPoupanca +=v;
}
public void transfereCC(int v){
saldoPoupanca -=v;
saldoCC +=v;
}
public int saldoTotal(){
return (saldoPoupanca + saldoCC);
}
}
Produtorpublic class Produtor implements Runnable{
private Conta c;
private Random r= new Random();
public Produtor(Conta _c){
c= _c;
}
public void run(){
while (true){
c.transfereCC(r.nextInt(1000));
c.transferePoupanca(r.nextInt(500));
}
}
}
Consumidorpublic class Consumidor implements Runnable{
private Conta c;
private int saldoInicial;
public Consumidor(Conta _c, int _saldoInicial){
c= _c;
saldoInicial=_saldoInicial;
}
public void run(){
int saldo;
while (true){
saldo= c.saldoTotal();
if (saldo != saldoInicial){
System.out.println("Saldo errado = "+saldo);
Thread.currentThread().yield();
}
}
}
}
Sincronizando acessos concorrentes
Synchronized Evita a execuo concorrente das threads
Como definir a sincronizao Mtodos
public synchronized transfereCC(int v); public synchronized transferePoupanca(int v); public synchronized saldoTotal();
Quando um mtodo definido como synchronized, ocorre um bloqueio, evitando a execuo No mtodo Entre mtodos synchronized da classe
Exerccio
1) Altere o cdigo da transferncia de conta para que o mesmo funcione corretamente
2) Verifique o funcionamento da aplicao SerialNumberGenerator
a) Identifique o problema
b) Faa as alteraes necessrias
Utilizando tipos de dados sincronizados
AtomicInteger, AtomicLong boolean compareAndSet(expectedValue,
updateValue);
addAndGet (int delta)
incrementAndGet()
AtomicReference boolean compareAndSet(expectedValue,
updateValue);
getAndSet(V newValue)
Tipos de dados sincronizados
Os tipos Queue (fila) LinkedQueue (lista) no pacote java.util no so sincronizados
Tipos de dados thread-safe so definidos no pacote java.util.concurrent
Interface BlockingQueue() Classe: ArrayBlockingQueue
void put(E e);
E take();
ArrayBlockingQueue
class Main() {
// Instanciando
private ArrayBlockingQueue buffer= new
ArrayBlockingQueue(5); // buffer de 5 posies
}
// inserindo elementos no buffer
buffer.put(new Integer(5));
//removendo elementos do buffer
valor= buffer.take();
Exerccio
Implemente duas Threads, uma produtora e uma consumidora O Produtor dever gerar 1000 nmeros e colocar
no buffer compartilhado para ser consumido pela Thread Consumidor
Utilize a classe BlockingQueue como buffer compartilhado
Material complementar
Semforos
Proposto por Dijkstra(1965)
Sincronizao que no necessita de espera ativa
Semforo S varivel inteira
Duas operaes S: acquire() e release()
Operaes atmicas
Semforo
Binrio: varia entre 0 e 1
Contador: valor inteiro
Implementao de semforos
Deve garantir que dois processos no executem acquire () e release () no mesmo semforo ao mesmo tempo
A implementao do acquire e release torna-se o problema de seo crtica. Espera ativa
Algumas aplicaes podem ficar muito tempo na seo crtica.
Implementao de semforo sem espera ativa
Cada semforo tem sua fila de espera. Cada posio da fila de espera tem dois campos: valor (tipo inteiro)
ponteiro para o prximo elemento da lista
Duas operaes:
block coloca o processo que esta adquirindo o semforo na fila apropriada.
wakeup remove o processo que esta na fila de espera e coloca na fila de prontos.
Implementao de semforo sem espera ativa
Acquire()
Release()
Semafros em Java Exemplo:import java.util.concurrent.Semaphore;
public class ThreadInterface implements Runnable{
Semaphore sem= new Semaphore(1);
public void run() {
sem.acquire();
for (int i=0; i
Bloqueios e variveis de condio
Menor overhead que semforos e synchronized
Implementao mais eficiente no Java
Variveis de condio so utilizadas caso seja necessrio bloquear a execuo no meio da seo crtica
Exemplo: Lockimport java.util.concurrent.locks.*;
public class ThreadInterface implements Runnable{
Lock mutex= new Lock();
public void run() {
mutex.lock();
for (int i=0; i
Exemplo: Variveis de condioclass ProducerConsumer {
Lock mutex= new Lock();
Condition cond= mutex.newCondition();
static class Produtor extends Runnable{
public void run() {
while (true) {
mutex.lock();
while (count == BUFFER_SIZE)
cond.await();
buffer [in] = nextProduced;
in = (in + 1) % BUFFER_SIZE;
count++;
cond.signal();
}
}
}
static class Consumidor extends Runnable{
public void run() {
while (true) {
mutex.lock();
while (count == 0)
cond.await();
nextConsumed= buffer[out];
out = (out + 1) % BUFFER_SIZE;
count--;
cond.signal();
}
}
}
..
..// mtodo Main
}
Deadlock e starvation
Deadlock dois ou mais processsos esperam infinitamente por eventos que somente podem ser gerados por processos no estado de espera
Seja S e Q dois semforos inicializados em 1
P0 P1
S.acquire(); Q.acquire();
Q.acquire(); S.acquire();
. .
. .
. .
S.release(); Q.release();
Q.release(); S.release();
Starvation bloqueio indefinido.