Introdução à Programação Orientada a Objetos com Java Paulo Borba Centro de Informática Universidade Federal de Pernambuco Conceitos Básicos de Concorrência.

Slides:



Advertisements
Apresentações semelhantes
|Introdução a Java para programadores Telis. Jogo de Dados simples O jogo é jogado por dois jogadores. Cada jogador faz sua jogada (lança um dado), e.
Advertisements

Soluções Iterativas com Laços
Programação Orientada a Objetos*
Modificadores Marco Antonio, Arquiteto de Software – TJDF Atualizado em Novembro/2008.
Programação Concorrente
Chain of Responsibility
Orientação a Objetos: Modificador Final para Métodos e Classes
Conceitos de Programação Paralela - 2
Walfredo Cirne Threads Walfredo Cirne
Sistemas Distribuídos
Programação Concorrente
Linguagem de Programação II
Concorrência Aula X.
Sincronização de Processos (3)
9 Controle de fluxo Seqüenciadores. Jumps. Escapes. Exceções.
Capítulo 9 Herança 1.
Estrutura de Dados em Java
Paradigmas de Linguagens de Programação Paradima da Programação Orientada à Objetos Professor: Armando Hage Belém-2008.
Threads sem Sincronização
Sincronização de Threads
JAVA: Conceitos Iniciais
O Mecanismo de Threads em Java 2. Criar uma classe herdeira da super classe Thread public class minhaThread extends Thread{ public class minhaThread extends.
Concorrência em Java Threads em Java.
Threads: Introdução e Implementação
Monitores.
Concorrência em Java Threads em Java.
Concorrência em Java Threads em Java.
Infra-Estrutura de Comunicação (IF678)
Chamada Remota de Procedimentos
1 Mobilidade de Código com μcode Projeto Giga Alexandre Lages
Paulo Borba Centro de Informática Universidade Federal de Pernambuco Classes Abstratas e Interfaces.
Os métodos equals() e hashCode()
Introdução à Programação Orientada a Objetos com Java Paulo Borba Centro de Informática Universidade Federal de Pernambuco Programação Imperativa (e Ponteiros.
Orientação a Objetos e Java Graduação em Ciência da Computação
Paulo Borba Centro de Informática Universidade Federal de Pernambuco
Concorrência e thread Petrônio Júnior(pglj) Márcio Neves(mmn2)
Linguagem II Exceções.
Wagner Santos C. de Jesus
Aula Prática 1 Monitoria IP/CC (~if669). Verificação Dinâmica de Tipos Métodos de superclasses e subclasses: Uso de métodos de subclasses quando se é.
Programação com Threads
Transações Concorrentes
Introdução às Java Threads
Orientação a Objetos e Java Graduação em Ciência da Computação  Centro de Informática, UFPE Alexandre Mota
Java Kickstart, day 2 Semelhanças com linguagem C.
Implementação Orientada a Objetos – Aula 05 Construtores e sobrecarga de métodos Prof. Danielle Martin Universidade de Mogi das Cruzes
Orientação a Objetos e Java Graduação em Ciência da Computação  Centro de Informática, UFPE Alexandre Mota (com material da Qualiti Software Process)
Semáforos n Variáveis compartilhadas são globais n Acesso a variáveis ocorre em procedimentos, mas podem estar espalhados pelo programa n Exige consulta.
Paulo Borba e Augusto Sampaio Centro de Informática Universidade Federal de Pernambuco Especificação de Sistemas Distribuídos.
Coleções, Genéricos, Threads Marco Antonio. Collection Principais métodos da interface Collection.
Orientação a Objetos e Java Graduação em Ciência da Computação  Centro de Informática, UFPE Alexandre Mota
Classes Abstratas e Interface
Herança e Arquitetura em camadas
Orientação a Objetos e Java Graduação em Ciência da Computação  Centro de Informática, UFPE Alexandre Mota
Copyright 1998, Departamento de Informática da UFPE. Todos os direitos reservados sob a legislação em vigor. Variáveis e métodos estáticos, Passagem de.
Socket em Java.
Sistemas Distribuídos Aula 05 – Programação Multithread/Paralela
Aula prática de Concorrência Equipe de Monitoria: Bruno Pereira - bpe Davi Pires - dpr Guilherme Barros – gbs2 Thiago Cavalcanti - trc.
Copyright 2000, Departamento de Informática, UFPE. Todos os direitos reservados sob a legislação em vigor. Orientação a Objetos e Java.
Grupos de Threads em Java
Programação com Threads Threads Java como um Estudo de Caso.
Java Threads.
Paulo Borba Centro de Informática Universidade Federal de Pernambuco Exceções.
Capítulo 8 Threads.
Orientação a Objetos e Java Graduação em Ciência da Computação  Centro de Informática, UFPE Alexandre Mota
Orientação a Objetos e Java Graduação em Ciência da Computação  Centro de Informática, UFPE Alexandre Mota
Infra-Estrutura de Comunicação (IF678) Aula Prática 03 – CIn/UFPE Davi Duarte Cynthia Raphaella Ivan França Jéssica Barbalho Larissa Paz Paulo Fernando.
CURSO JAVA BÁSICO Módulo 9 – slide 1 Módulo 10 Threads.
ProgramaçãoConcorrente Glêdson Elias
Arleys Pereira Nunes de Castro - Mestrando : Modelagem computacional (SENAI-MCTI) Especialista : Sistema distribuídos
ProgramaçãoConcorrente Glêdson Elias
Transcrição da apresentação:

Introdução à Programação Orientada a Objetos com Java Paulo Borba Centro de Informática Universidade Federal de Pernambuco Conceitos Básicos de Concorrência

Execução sequencial Conta c; c = new Conta(“12-3”); c.creditar(100); c.debitar(80); System.out.print( c.getSaldo()); Os comandos são executados em seqüência, um após o outro O resultado da execução é sempre o mesmo: a conta tem $R 20,00 de saldo

Nas linguagens concorrentes... A execução também pode ser concorrente: dois ou mais comandos podem ser executados ao mesmo tempo Na execução sequencial, só um comando é executado por vez

A execução concorrente é útil para... Permitir que vários usuários utilizem os serviços de um dado sistema ao mesmo tempo Aumentar a eficiência de um programa (mas cuidado!) Fachada GUI

A execução concorrente é possível pois... Pode-se executar cada um dos comandos em um processador diferente (paralelismo), ou dividir o tempo da execução de um processador para executar os vários comandos, parte a parte Os comandos normalmente não são atômicos

Os comandos e suas partes double tmp = saldo; tmp = tmp + 5; saldo = tmp; Até uma atribuição como saldo = saldo + 5; é executada por partes, similarmente à execução da seqüência de comandos abaixo:

Execução concorrente Conta c; c = new Conta(“12-3”); c.creditar(100) || c.debitar(80) System.out.print( c.getSaldo()); Os comandos podem ser executados ao mesmo tempo Pode-se executar parte de um, parte de outro, arbitrariamente, até completar a execução dos dois

Mais execução concorrente Conta c; c = new Conta(“12-3”); c.creditar(100) || c.debitar(80) System.out.print( c.getSaldo()); Pode-se também executar o primeiro por completo e depois o segundo por completo, ou vice-versa A escolha é arbitrária, feita pelo interpretador

Concorrência e não determinismo Conta c; c = new Conta(“12-3”); c.creditar(100) || c.debitar(80) System.out.print( c.getSaldo()); A execução pode gerar mais de um resultado! Depende da ordem escolhida para executar as partes dos comandos A escolha é arbitrária, feita pelo interpretador

Conta: segura em um ambiente sequencial... class Conta {... private double saldo = 0; void creditar(double vc) { 1 double tmpc = saldo; 2 tmpc = tmpc + vc; 3 saldo = tmpc; } void debitar(double vd) { A double tmpd = saldo; B tmpd = tmpd - vd; C saldo = tmpd; }

Mas em um ambiente concorrente... c.creditar(100) || c.debitar(80) Várias seqüências de execução dos comandos são possíveis: A B C (resultado: 20 ) A B C (resultado: 20 ) 1 A 2 3 B C (resultado: -80 ) A 1 2 B C 3 (resultado: 100 )...

Ambiente concorrente e interferências A execução de um comando pode interferir na execução de um outro comando As interferências ocorrem quando os comandos compartilham (concorrem) pelos mesmos recursos (atributos, variáveis, etc.) Resultados não desejados podem ser gerados

Para evitar interferências indesejadas... Temos que controlar o acesso a recursos compartilhados Temos que proibir a realização de determinadas seqüências de execução Temos que sincronizar as execuções: uma espera pelo término da outra

Em Java, para sincronização, use synchronized Só um método synchronized pode ser executado em um objeto por vez Os outros ficam esperando! Vários métodos não sincronizados podem ser executados, no mesmo objeto, ao mesmo tempo que um método synchronized

Conta: segura em um ambiente concorrente... class Conta {... private double saldo = 0; synchronized void creditar(double vc) { 1 double tmpc = saldo; 2 tmpc = tmpc + vc; 3 saldo = tmpc; } synchronized void debitar(double vd) { A double tmpd = saldo; B tmpd = tmpd - vd; C saldo = tmpd; }

Conta: segura em um ambiente concorrente... class Conta {... private double saldo = 0; private String numero; synchronized double getSaldo() { return saldo; } String getNumero() { return numero; } Não precisaria sincronizar se fosse int: race condition que não implicaria em interferência

Com sincronização, eliminamos interferências... c.creditar(100) || c.debitar(80) Só algumas seqüências de execução são permitidas: A B C (resultado: 20 ) A B C (resultado: 20 ) O programa é determinístico: só um resultado é possível

O comando synchronized de Java synchronized void m(...) { corpo } void m(...) { synchronized(this) { corpo } O modificador Equivalentes O comando; impede a execução simultânea de trechos de códigos sincronizados no mesmo argumento

Conta: não segura em um ambiente concorrente... class Conta {... private double saldo = 0; void creditar(double vc) { double tmpc; synchronized(this) {tmpc = saldo;} tmpc = tmpc + vc; synchronized(this) {saldo = tmpc;} } Não há race conditions, mas pode haver interferências…

Notação alternativa para execução concorrente Conta c; c = new Conta(“12-3”); fork{c.creditar(100);}; fork{c.debitar(80);}; System.out.print( c.getSaldo()); Não herda lock do pai…

Como solicitar a execução concorrente em Java? O operador de execução concorrente ||, nem fork, não existe em Java! Mas Java permite criar threads Seqüências ou fluxos de execução que podem ser executados concorrentemente Os comandos a serem executados são “empacotados” como threads Objetos da classe java.lang.Thread

A classe Thread de Java Subclasses de Thread redefinem o método run Os comandos a serem executados por um thread são os comandos do corpo do método run Execução concorrente = Criação e início de threads

c.creditar(1)||c.debitar(8) em Java Thread c = new Credito(...); Thread d = new Debito(...); c.start(); d.start(); try { c.join(); d.join(); } catch(InterruptedException e) {...} Inicia a execução do thread Espera pelo término da execução do thread Subclasses de Thread

Simulando o operador de execução concorrente Thread a = new ThreadA(...); Thread b = new ThreadB(...); a.start(); b.start(); try { a.join(); b.join(); } catch(InterruptedException e) {...} A || B corresponde a

Um comando a ser executado concorrentemente... class Credito extends Thread { private Conta conta; private double val; Credito(Conta c, double v) { conta = c; val = v; } public void run() { conta.creditar(val); } O comando a ser executado ao mesmo tempo que outro

E o outro comando... class Debito extends Thread { private Conta conta; private double val; Creditar(Conta c, double v) { conta = c; val = v; } public void run() { conta.debitar(val); } Aqui poderia ter vários comandos, em seqüência ou concorrentes também

Mas quando herança é um problema... class Debito implements Runnable { private Conta conta; private double val; Creditar(Conta c, double v) { conta = c; val = v; } public void run() { conta.debitar(val); } Uma alternativa é implementar a interface Runnable...

c.creditar(1)||c.debitar(8) em Java, com Runnable Thread c = new Credito(...); Thread d; d = new Thread(new Debito(...)); c.start(); d.start(); try { c.join(); d.join(); } catch(InterruptedException e) {...} Subclasse de Thread Implementação de Runnable

Sincronização com synchronized A execução de um thread t tem que esperar pela execução de outro thread u quando u está executando um método sincronizado e t quer começar a executar um método sincronizado do mesmo objeto Pode ser o mesmo método ou não

Sincronização com wait A execução de um thread t tem que esperar pela execução de outro thread u quando A semântica da aplicação requer que uma operação de t só seja executada em condições que podem ser garantidas por uma operação de u A aplicação solicita a espera

Impedindo débitos além do limite class Conta {... private double saldo = 0; synchronized void debitar(double v) { while (saldo < v){ wait(); } saldo = saldo - v; }... Interrompe a execução do método e do thread associado, que só volta a executar quando notificado por outro thread Assumindo que débitos além do limite não geram erros, mas espera...

Por que while e não if ? class Conta {... private double saldo = 0; synchronized void debitar(double v) { while (saldo < v){ wait(); } saldo = saldo - v; }... A notificação avisa que talvez seja possível realizar o débito, mas não garante! Temos que testar de novo...

Avisando que o saldo aumentou class Conta {... synchronized void creditar(double v) { saldo = saldo + v; notifyAll(); } Avisa (notifica) a todos os threads que estavam esperando pela execução de um método desse ( this ) objeto

O método wait... Só pode ser chamado dentro de um método synchronized Coloca o thread executando o comando para esperar por uma notificação Libera a restrição de sincronização outro método sincronizado vai poder começar a executar no mesmo objeto

Os métodos notify e notifyAll O método notifyAll acorda todos os threads esperando para executar um método do objeto que executou o notifyAll O método notify só acorda um dos processos a escolha é arbitrária, feita pelo interpretador

Cuidado com concorrência! Os mecanismos para sincronização diminuem a eficiência do sistema e podem complicar o código O sistema pode entrar em deadlock! Todos os threads parados, um esperando pelo outro O sistema pode entrar em livelock! Threads executando mas não gerando nada que possa ser observado pelo usuário

Modelos alternativos para concorrência Escalonamento não pré-emptivo a transferência de controle ocorre somente em pontos bem definidos da execução de uma tarefa Escalonamento pré-emptivo uma transferência de controle entre tarefas pode ocorrer a qualquer momento Troca de mensagens

Indo além... Terminação de threads pais e filhos daemons Prioridades em threads Thread do AWT Concorrência e arquitetura em camadas: BD pode eliminar a necessidade de sincronizar classes básicas

Claus Reinke at m As you are aware, simply assigning to channel in one thread doesn'tbring the value into main memory, and simply reading in the otherdoesn't ensure that what we are reading is consistent with mainmemory. So Joe R. Hacker has searched the JLS for a solution (which,on some fine Friday 13th, you might find in your codebase). According to JLS, *all* pending writes are committed to main memorybefore releasing *any* lock, and *all* first reads after acquiring*any* lock have to be preceded by a lookup in main memory. So, byusing some dummy synch after writing and before reading, the codeensures that channel data travels from thread to thread, via mainmemory. Removing the dummy synch increases the likelihood of thetests to fail, as the code no longer explicitly ensuressynchronisation, but implementations are free to add any number ofextra synchs, so the tests might still go through. class PlayingField { static int channel; // public PlayingField() { channel = 0; } public static void init() { channel = 0; } static void dummy() { // synchronized (new Object()) { } //1 // System.out.println("hithere"); //2 // System.out.println("hi"+"there"); //3 new StringBuffer("hi").append("there"); //4 // new StringBuffer("hithere"); //5 // new String("hithere"); //6 // new Object(); //7 } static public void codeA(int no) { int count=0,got; channel = no; /* */ dummy(); got = channel; while (got==no) { /* */ dummy(); got = channel; count++; } // channel = 0; /* */ dummy(); if (got==-no) System.err.println("A ("+no+") ["+count+"] done "); else System.err.println("A ("+no+") ["+count+"] failed "); } static public void codeB(int no) { int count=0,got; got = channel; while (got<=0) { /* */ dummy(); got = channel; count++; } channel = -no; /* */ dummy(); if (got==no) System.err.println("B ("+no+") ["+count+"] done "); else System.err.println("B ("+no+") ["+count+"] failed "); }} // ready? okay, now let's put that code through a few tests;// I do assume you've kept the original for comparison?-) public class Tst { static Object lock = new Object(); static int no=0; // static PlayingField playingField; static volatile boolean ready=false,readyA=false,readyB=false; static void tst() { synchronized (lock) { no++; System.err.println("\ntst ["+no+"]"); // playingField = new PlayingField(); PlayingField.init(); ready = false; readyA = false; readyB = false; } Thread A = new Thread() { public void run() { int no=0; synchronized (lock) { no=Tst.no; readyA=true; } while (!ready) {}; PlayingField.codeA(no); } }; Thread B = new Thread() { public void run() { int no=0; synchronized (lock) { no=Tst.no; readyB=true; } while (!ready) {}; PlayingField.codeB(no); } }; B.start(); A.start(); while (!(readyA && readyB)) {} ready = true; for(int i=0;i< ;i++) {} // try { Thread.sleep(1000); } catch (InterruptedException e) {} // try { A.join(); } catch (InterruptedException e) {} // try { B.join(); } catch (InterruptedException e) {} } public static void main(String[] args) { for (int i=0; i<100; i++) { tst(); } }}