• Nenhum resultado encontrado

Introdução à Programação

N/A
N/A
Protected

Academic year: 2022

Share "Introdução à Programação"

Copied!
39
0
0

Texto

(1)

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

(2)

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

(3)

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

(4)

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 GUI

GUI

(5)

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

(6)

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:

(7)

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

(8)

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

(9)

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

(10)

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;

}

(11)

Mas em um ambiente concorrente...

c.creditar(100) || c.debitar(80) Várias seqüências de execução dos comandos são possíveis:

1 2 3 A B C (resultado: 20)

A B C 1 2 3 (resultado: 20)

1 A 2 3 B C (resultado: -80)

A 1 2 B C 3 (resultado: 100 )

•...

(12)

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

(13)

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

(14)

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

(15)

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;

}

(16)

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

(17)

Com sincronização,

eliminamos interferências...

c.creditar(100) || c.debitar(80) Só algumas seqüências de execução

são permitidas:

1 2 3 A B C (resultado: 20)

A B C 1 2 3 (resultado: 20)

O programa é

determinístico: só um resultado é possível

(18)

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

(19)

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…

(20)

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…

(21)

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

(22)

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 =

(23)

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

(24)

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

(25)

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

(26)

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

(27)

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...

(28)

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

(29)

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

(30)

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

(31)

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 ...

(32)

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...

(33)

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

(34)

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

(35)

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

(36)

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

(37)

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

(38)

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

(39)

Claus Reinke C.Reinke@ukc .ac.uk at

[email protected] 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<100000000;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(); }   }}

Referências

Documentos relacionados

A entrevista inicial permite a avaliação do analisando em potencial no que diz respeito à sua adequação para a análise e representa a melhor oportunidade para que o

BOERO (1967), mesmo sem fazer referências a búfalos, afirma que a época do ano mais favorável à apresentação da As- pergilose nos animais domésticos, na Argentina, é o final do

Primeiramente, um conhecimento, tanto do “livro da natureza” quanto uma releitura bíblico- teológica a partir da teologia da criação; em segundo lugar, o cuidado

O SUBPROCURADOR-GERAL DE JUSTIÇA, PARA A ÁREA JURÍDICO-INSTITUCIONAL, usando das atribuições que lhe foram delegadas pela PORTARIA Nº 4574/2013-MP/PGJ, de 24 de Julho de

Assim, a deposição temporária de proteínas da matriz do esmalte sobre a superfície radicular seria um passo essencial para induzir a neoformação de cemento acelular, que pode

“De qualquer maneira, não posso reclamar do pouco espaço disponível”, sorri Marco e completa: para todo o planejamento já pensamos com antecedência. exatamente o que iria

 O desempenho na Tarefa de reconhecimento de palavras com interferência semântica teve uma baixa correlação com os desempenhos nas tarefas que avaliaram a

Convencionam as partes que, exclusivamente para os empregados que mantêm contrato de trabalho com a mesma empresa ou, empresa do mesmo grupo econômico há mais de 10 (dez) anos e