Problema com Threads - Produto Consumidor

17 respostas
gugabarc

Meu programa possui Clientes, que vao até uma Agencia Bancaria e cada cliente é atendido por um Caixa, sao 5 Caixas ao todo.
Cada Cliente possui uma Arraylist de requisicoes para fazer ao caixa.

Tem uma classe produtor que implementa Runnable e vai colocando Clientes em uma ArrayBlockingQueue com o metodo put().
Tem a classe Caixa que implementa Runnable e vai pegando cada Cliente do ArrayBlockingQueue com o metodo take().

package Threads;


public class Requisicao{

    //Se talaoCheque=true, entao a requisicao e de talao de cheques
    private boolean talaoCheque;
    private boolean realizado;

    public Requisicao(boolean talaoCheque){
        this.talaoCheque = talaoCheque;
        realizado = false;
    }

    public Requisicao(){
        this.talaoCheque = false;
    }

    public boolean getRealizado(){
        return realizado;
    }

    public void setRealizado(boolean realizado){
        this.realizado = realizado;
    }

    public boolean getRequisicao(){
        return talaoCheque;
    }

}
package Threads;

import java.util.ArrayList;
import java.util.Random;


public class Cliente {

    private ArrayList<Requisicao> listRequisicoes;
    private boolean clientePreferencial;
    private static Random gerador = new Random();
    private int numeroRequisicoes;
    //atrib teste
    private int nome;

    //metodo teste
    public void setNome(int x){
        nome = x;
    }

    //metodo teste
    public int getNome(){
       return nome;
    }

    public Cliente(){
        listRequisicoes = new ArrayList<Requisicao>();
        numeroRequisicoes = gerador.nextInt(5)+1;
        clientePreferencial = false;
        geradorRequisicoes();
    }

    public Cliente(boolean clientePreferencial, int nome){
        listRequisicoes = new ArrayList<Requisicao>();
        //Gera numero de requisicoes. Aprimorar.
        numeroRequisicoes = gerador.nextInt(5)+1;
        this.clientePreferencial = clientePreferencial;
        geradorRequisicoes();
        this.nome = nome;
    }

    private void geradorRequisicoes(){
        int randomRequisitos = 0;
        for(int i = 0; i < numeroRequisicoes; i++){
            randomRequisitos = gerador.nextInt(10)+1;
            if(randomRequisitos <= 2){
                listRequisicoes.add(new Requisicao(true));
            }
            else{
                listRequisicoes.add(new Requisicao(false));
            }
        }
    }

    public boolean getClientePreferencial(){
        return clientePreferencial;
    }

    public ArrayList<Requisicao> getListaRequisicoes(){
        return listRequisicoes;
    }

}
package Threads;

import java.util.Random;
import java.util.concurrent.BlockingQueue;

public class Produtor implements Runnable {

    private final BlockingQueue<Cliente> filaClientes;
    private Random gerador = new Random();
    private int tamanho;
    

    public Produtor(int tamanho, BlockingQueue<Cliente> filaClientes) {
        this.filaClientes = filaClientes;
        this.tamanho = tamanho;
    }

    public void run() {
        try {
            for (int i = 0; i < tamanho; i++) {
                int contador = gerador.nextInt(10) + 1;
                if (contador <= 4) {
                    filaClientes.put(new Cliente(true, i));

                } else {
                    filaClientes.put(new Cliente(false, i));
                }
                System.out.println("Chegando cliente...");
            }
        } catch (InterruptedException ex) {
            System.out.println(ex.getMessage());
        }
    }
}
/*
package Threads;

import java.util.concurrent.BlockingQueue;

public class Caixa implements Runnable {

    private boolean preferencial;
    private int numeroCaixa;
    private final BlockingQueue<Cliente> filaClientes;

    public Caixa(int numeroCaixa, boolean preferencial, BlockingQueue<Cliente> filaClientes){
        this.numeroCaixa = numeroCaixa;
        this.preferencial = preferencial;
        this.filaClientes = filaClientes;
    }

    public int getNumeroCaixa(){
        return numeroCaixa;
    }

    public void run(){

        while(true){
            try {
                Thread.sleep(2000);
                System.out.println("Caixa: " + getNumeroCaixa() + "   Atendendo cliente: " + filaClientes.take().getNome());
            } catch (InterruptedException ex) {
                System.out.println(ex.getMessage());
            }
        }
    }

}
package Threads;

import java.util.ArrayList;
import java.util.Random;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Agencia {

    public static void main(String args[]) {

        ArrayBlockingQueue<Cliente> filaClientes = new ArrayBlockingQueue<Cliente>(100);
        ExecutorService executor = Executors.newFixedThreadPool(5);

        executor.execute(new Produtor(30, filaClientes));
        executor.execute(new Caixa(1, false, filaClientes));
        executor.execute(new Caixa(2, false, filaClientes));
        executor.execute(new Caixa(3, false, filaClientes));
        executor.execute(new Caixa(4, false, filaClientes));
        executor.execute(new Caixa(5, false, filaClientes));
        
        executor.shutdown();
    }
}

O resultado da execução é:

Chegando cliente...
Chegando cliente...
Chegando cliente...
Chegando cliente...
Chegando cliente...
Chegando cliente...
Chegando cliente...
Chegando cliente...
Chegando cliente...
Chegando cliente...
Chegando cliente...
Chegando cliente...
Chegando cliente...
Chegando cliente...
Chegando cliente...
Chegando cliente...
Chegando cliente...
Chegando cliente...
Chegando cliente...
Chegando cliente...
Chegando cliente...
Chegando cliente...
Chegando cliente...
Chegando cliente...
Chegando cliente...
Chegando cliente...
Chegando cliente...
Chegando cliente...
Chegando cliente...
Chegando cliente...
Caixa: 1 Atendendo cliente: 0
Caixa: 3 Atendendo cliente: 2
Caixa: 2 Atendendo cliente: 3
Caixa: 4 Atendendo cliente: 1
Caixa: 5 Atendendo cliente: 4
Continua...

Ou seja, os clientes estão sendo pegos do ArrayBlockingQueue fora de ordem, alguem sabe o motivo?

Muito obrigado,

Gustavo

17 Respostas

E

Você esperaria que os caixas atendessem em que ordem? Que eu saiba, se há vários consumidores (caixas), cada qual pode consumir na velocidade que quiser. Como você tem uma fila única, o cliente a ser atendido pode ir para qualquer caixa.

gugabarc

acho que tu nao entendeu, os clientes estão sendo atendidos fora de ordem, deveria ser assim:
Caixa x Atendendo Cliente 0
Caixa a Atendendo Cliente 1
Caixa b Atendendo Cliente 2
Caixa c Atendendo Cliente 3
Caixa x Atendendo Cliente 4
Caixa a Atendendo Cliente 5
Caixa c Atendendo Cliente 6
Caixa b Atendendo Cliente 7

Tiago.Argolo

Não sei se este é o seu objetivo, mas você pretende executar uma ordem exata com Threads?

Caso seja esse o seu objetivo, infelizmente não tem como você definir uma ordem exata no escalonamento das threads.

Cabe a JVM e ao processador decidir qual Thread ser executada, tendo a possibilidade de deixar uma Thread em modo executável e deixar a outra em modo executando como assim decidir.

Se quiser comprovar isto, rode sua aplicação várias vezes e veja que a ordem sempre estará mudando… Existe uma maneira de SUGERIR que a ordem seja exata usando as prioridades… com o método: .setPriority() .Porém, como dito anteriormente, nada é garantido quando se trata de Thread.

Uma dica é nunca deixar uma funcionalidade importante na sua aplicação dependente da ordem de execução de mais de uma Thread.

Espero ter ajudado! Abraço.
gugabarc

Entendi, mas os clientes devem ser atendidos por ordem de chegada, na forma de fila, utilizando uma ArrayBlockingQueue me garante que serão atendidos dessa forma pelos caixas? Ou podem ser atendidos foram de ordem, assim precisando alterar algo?

sergiotaborda

gugabarc:

O resultado da execução é:

Isso é o esperado. Não ha garantia de ordem quando se usam threads em java. Isto é assim, sempre.
O que interessa no padrão produtor-consumidor é que tudo o que produtor produz
seja consumido. Tão simples assim. Sempre preocupação de ordem.

Vc não deveria esperar por uma ordem especifica. Esse é o seu problema. O codigo está funcionado corretamente.

gugabarc

É que o enunciado do problema define que os clientes devem ser atendidos pela ordem q chegam.

Tiago.Argolo

No método onde está sendo exibido as informações, você pode definí-lo como Synchronized. A partir daí apenas 1 Thread por vez poderá acessar este método… Desde que ou ele seja estático ou todas as Threads estão referenciado ao mesmo objeto onde ele se encontra.

O Collection ArrayList, se não me falhe a memória, é por padrão Synchronized. Mas já que o método onde ele poderá estar será Synchronized, seria redundância de código.

Dá uma pesquisada sobre Thread’s e tu irá encontar muita coisa sobre isto… mas lembre-se: Nunca espere garantias em Threads :smiley:

abraço!

maschiojv

Olá Gustavo,

você deve passar true para o construtor de ArrayBlockingQueue

na linha 13 da classe Caixa:

ArrayBlockingQueue<Cliente> filaClientes = new ArrayBlockingQueue<Cliente>(100, true);

assim você diz que quer que a fila seja ordenada no padrão FIFO.

E

Uai, escrevi um programa parecido e ele não bagunça a ordem.

import java.util.concurrent.*;
import java.util.*;

class Consumidor implements Runnable {
    public Consumidor (int nConsumidor, ArrayBlockingQueue<Item> abq) { this.nConsumidor = nConsumidor; this.abq = abq; }
    public String toString() { return String.format ("Consumidor %d", nConsumidor); }
    public void run () {
        try {
            while (true) {
                Thread.sleep (r.nextInt (200));
                Item it = abq.take();
                System.out.println ("Consumidor " + nConsumidor + " consumiu " + it);
            }
        } catch (InterruptedException ex) {
            System.out.printf ("O produtor %d foi interrompido. %n", nConsumidor);
        }
    }
    private int nConsumidor;
    private ArrayBlockingQueue<Item> abq;
    private static Random r = new Random();
}

class Produtor implements Runnable {
    public Produtor (int nProdutor, int nItens, ArrayBlockingQueue<Item> abq) { this.nProdutor = nProdutor; this.nItens = nItens; this.abq = abq; }
    public String toString() { return String.format ("Produtor %d", nProdutor); }
    public void run () {
        try {
            for (int i = 1; i <= nItens; ++i) {
                Item it = new Item (nProdutor, i); 
                abq.put (it);
                Thread.sleep (r.nextInt (20));
                System.out.println ("Produtor produziu " + it);
            }
        } catch (InterruptedException ex) {
            System.out.printf ("O produtor %d foi interrompido. %n", nProdutor);
        }
    }
    private int nProdutor;
    private int nItens;
    private ArrayBlockingQueue<Item> abq;
    private static Random r = new Random();
}

class Item {
    public Item (int nProdutor, int nItem) { this.nProdutor = nProdutor; this.nItem = nItem; }
    public String toString() { return String.format ("Item %02d de %02d", nItem, nProdutor); }
    private int nItem, nProdutor;
}

class TesteProdutorConsumidor {
    public TesteProdutorConsumidor(int nItens, int nProdutores, int nConsumidores, int tamFila) {
        this.nItens = nItens; this.nProdutores = nProdutores; this.nConsumidores = nConsumidores;
        this.tamFila = tamFila;
        itens = new ArrayBlockingQueue<Item> (tamFila, true); // fair = true -> se houver threads bloqueadas, serão processadas em ordem FIFO
    }
    public void startTest() {
	ExecutorService executor = Executors.newFixedThreadPool (nProdutores + nConsumidores);
        for (int i = 1; i <= nProdutores; ++i) {
            executor.execute (new Produtor (i, nItens, itens));
        }       
        for (int i = 1; i <= nConsumidores; ++i) {
            executor.execute (new Consumidor (i, itens));
        }       
        try { Thread.sleep (20000); } catch (InterruptedException ex) { }
        executor.shutdownNow();
    }
    public static void main(String[] args) {
        TesteProdutorConsumidor tpc = new TesteProdutorConsumidor (30, 1, 5, 100);
        tpc.startTest();
    }
    private int nItens, nProdutores, nConsumidores, tamFila;
    private ArrayBlockingQueue<Item> itens;
}

Uma das saídas possíveis:

Produtor produziu Item 01 de 01
Produtor produziu Item 02 de 01
Produtor produziu Item 03 de 01
Produtor produziu Item 04 de 01
Produtor produziu Item 05 de 01
Produtor produziu Item 06 de 01
Produtor produziu Item 07 de 01
Produtor produziu Item 08 de 01
Produtor produziu Item 09 de 01
Consumidor 3 consumiu Item 01 de 01
Produtor produziu Item 10 de 01
Produtor produziu Item 11 de 01
Produtor produziu Item 12 de 01
Produtor produziu Item 13 de 01
Produtor produziu Item 14 de 01
Consumidor 1 consumiu Item 02 de 01
Produtor produziu Item 15 de 01
Produtor produziu Item 16 de 01
Consumidor 5 consumiu Item 03 de 01
Consumidor 2 consumiu Item 04 de 01
Produtor produziu Item 17 de 01
Consumidor 4 consumiu Item 05 de 01
Produtor produziu Item 18 de 01
Produtor produziu Item 19 de 01
Produtor produziu Item 20 de 01
Produtor produziu Item 21 de 01
Consumidor 1 consumiu Item 06 de 01
Produtor produziu Item 22 de 01
Consumidor 4 consumiu Item 07 de 01
Produtor produziu Item 23 de 01
Produtor produziu Item 24 de 01
Produtor produziu Item 25 de 01
Consumidor 5 consumiu Item 08 de 01
Produtor produziu Item 26 de 01
Consumidor 5 consumiu Item 09 de 01
Produtor produziu Item 27 de 01
Consumidor 5 consumiu Item 10 de 01
Consumidor 5 consumiu Item 11 de 01
Consumidor 3 consumiu Item 12 de 01
Consumidor 2 consumiu Item 13 de 01
Produtor produziu Item 28 de 01
Produtor produziu Item 29 de 01
Consumidor 1 consumiu Item 14 de 01
Produtor produziu Item 30 de 01
Consumidor 2 consumiu Item 15 de 01
Consumidor 3 consumiu Item 16 de 01
Consumidor 5 consumiu Item 17 de 01
Consumidor 1 consumiu Item 18 de 01
Consumidor 1 consumiu Item 19 de 01
Consumidor 1 consumiu Item 20 de 01
Consumidor 4 consumiu Item 21 de 01
Consumidor 2 consumiu Item 22 de 01
Consumidor 3 consumiu Item 23 de 01
Consumidor 5 consumiu Item 24 de 01
Consumidor 2 consumiu Item 25 de 01
Consumidor 4 consumiu Item 26 de 01
Consumidor 1 consumiu Item 27 de 01
Consumidor 3 consumiu Item 28 de 01
Consumidor 5 consumiu Item 29 de 01
Consumidor 1 consumiu Item 30 de 01
O produtor 4 foi interrompido. 
O produtor 2 foi interrompido. 
O produtor 5 foi interrompido. 
O produtor 3 foi interrompido. 
O produtor 1 foi interrompido.
E

Mesmo havendo mais que um produtor, ArrayBlockingQueue não bagunça a ordem. Mude a linha

para

TesteProdutorConsumidor tpc = new TesteProdutorConsumidor (30, 2, 5, 100);

e veja que a ordem não é bagunçada.

Produtor produziu Item 01 de 02
Produtor produziu Item 01 de 01
Produtor produziu Item 02 de 02
Produtor produziu Item 02 de 01
Produtor produziu Item 03 de 02
Produtor produziu Item 04 de 02
Produtor produziu Item 05 de 02
Produtor produziu Item 03 de 01
Produtor produziu Item 04 de 01
Produtor produziu Item 06 de 02
Produtor produziu Item 05 de 01
Produtor produziu Item 07 de 02
Produtor produziu Item 08 de 02
Produtor produziu Item 06 de 01
Produtor produziu Item 09 de 02
Produtor produziu Item 07 de 01
Produtor produziu Item 10 de 02
Produtor produziu Item 08 de 01
Consumidor 5 consumiu Item 01 de 01
Consumidor 5 consumiu Item 01 de 02
Produtor produziu Item 09 de 01
Produtor produziu Item 11 de 02
Produtor produziu Item 10 de 01
Consumidor 2 consumiu Item 02 de 02
Produtor produziu Item 11 de 01
Produtor produziu Item 12 de 02
Produtor produziu Item 12 de 01
Produtor produziu Item 13 de 01
Consumidor 4 consumiu Item 02 de 01
Produtor produziu Item 13 de 02
Produtor produziu Item 14 de 01
Produtor produziu Item 14 de 02
Consumidor 3 consumiu Item 03 de 02
Produtor produziu Item 15 de 01
Consumidor 2 consumiu Item 03 de 01
Produtor produziu Item 15 de 02
Produtor produziu Item 16 de 01
Produtor produziu Item 17 de 01
Produtor produziu Item 16 de 02
Produtor produziu Item 18 de 01
Consumidor 1 consumiu Item 04 de 02
Produtor produziu Item 17 de 02
Produtor produziu Item 18 de 02
Produtor produziu Item 19 de 01
Consumidor 3 consumiu Item 05 de 02
Produtor produziu Item 19 de 02
Produtor produziu Item 20 de 01
Produtor produziu Item 20 de 02
Produtor produziu Item 21 de 02
Produtor produziu Item 21 de 01
Produtor produziu Item 22 de 01
Consumidor 4 consumiu Item 06 de 02
Produtor produziu Item 22 de 02
Produtor produziu Item 23 de 01
Produtor produziu Item 23 de 02
Consumidor 3 consumiu Item 04 de 01
Produtor produziu Item 24 de 01
Produtor produziu Item 25 de 01
Produtor produziu Item 24 de 02
Consumidor 5 consumiu Item 05 de 01
Produtor produziu Item 26 de 01
Produtor produziu Item 27 de 01
Consumidor 2 consumiu Item 07 de 02
Produtor produziu Item 28 de 01
Produtor produziu Item 25 de 02
Produtor produziu Item 26 de 02
Produtor produziu Item 29 de 01
Produtor produziu Item 30 de 01
Produtor produziu Item 27 de 02
Consumidor 2 consumiu Item 06 de 01
Consumidor 1 consumiu Item 08 de 02
Produtor produziu Item 28 de 02
Consumidor 2 consumiu Item 09 de 02
Produtor produziu Item 29 de 02
Produtor produziu Item 30 de 02
Consumidor 5 consumiu Item 07 de 01
Consumidor 1 consumiu Item 10 de 02
Consumidor 3 consumiu Item 08 de 01
Consumidor 5 consumiu Item 11 de 02
Consumidor 4 consumiu Item 09 de 01
Consumidor 3 consumiu Item 10 de 01
Consumidor 2 consumiu Item 12 de 02
Consumidor 1 consumiu Item 11 de 01
Consumidor 2 consumiu Item 12 de 01
Consumidor 2 consumiu Item 13 de 02
Consumidor 4 consumiu Item 13 de 01
Consumidor 2 consumiu Item 14 de 01
Consumidor 2 consumiu Item 14 de 02
Consumidor 1 consumiu Item 15 de 01
Consumidor 5 consumiu Item 15 de 02
Consumidor 3 consumiu Item 16 de 01
Consumidor 2 consumiu Item 16 de 02
Consumidor 2 consumiu Item 17 de 01
Consumidor 1 consumiu Item 18 de 01
Consumidor 3 consumiu Item 17 de 02
Consumidor 5 consumiu Item 19 de 01
Consumidor 4 consumiu Item 18 de 02
Consumidor 2 consumiu Item 19 de 02
Consumidor 1 consumiu Item 20 de 01
Consumidor 3 consumiu Item 20 de 02
Consumidor 4 consumiu Item 21 de 01
Consumidor 1 consumiu Item 21 de 02
Consumidor 5 consumiu Item 22 de 02
Consumidor 4 consumiu Item 22 de 01
Consumidor 3 consumiu Item 23 de 01
Consumidor 5 consumiu Item 23 de 02
Consumidor 2 consumiu Item 24 de 01
Consumidor 5 consumiu Item 24 de 02
Consumidor 1 consumiu Item 25 de 01
Consumidor 4 consumiu Item 26 de 01
Consumidor 4 consumiu Item 25 de 02
Consumidor 2 consumiu Item 27 de 01
Consumidor 1 consumiu Item 28 de 01
Consumidor 3 consumiu Item 29 de 01
Consumidor 4 consumiu Item 26 de 02
Consumidor 5 consumiu Item 27 de 02
Consumidor 4 consumiu Item 30 de 01
Consumidor 2 consumiu Item 28 de 02
Consumidor 4 consumiu Item 29 de 02
Consumidor 4 consumiu Item 30 de 02
O produtor 1 foi interrompido. 
O produtor 2 foi interrompido. 
O produtor 3 foi interrompido. 
O produtor 4 foi interrompido. 
O produtor 5 foi interrompido.
gugabarc

pois é, nossos programas estão parecidos, mas comigo continua embaralhando, mesmo botando true como parâmetro do ArrayBlockingQueue…

gugabarc

Acho que resolvi o problema, era só colocar o tempo do caixa para variar usando thread.sleep() com random…

Outra duvida que tenho, quero que meu produtor faça clientes durante 30 segundos, tem como fazer isso?

eu sempre pesquiso no google antes d perguntar, e caso nao ache a resposta eu pergunto aqui…

abraço e valeu a todos

E

Algo parecido com isto aqui:

private int nMilissegundos; // em algum lugar, preenchido com 30000 = 30 segundos

     public void run () {  
         try {  
             int nItem = 1;
             long start = System.currentTimeMillis();
             while (System.currentTimeMillis() - start <= nMilissegundos) {
                 Item it = new Item (nProdutor, i);   
                 abq.put (it);  
                 Thread.sleep (r.nextInt (20));  
                 System.out.println ("Produtor produziu " + it);  
             }  
         } catch (InterruptedException ex) {  
             System.out.printf ("O produtor %d foi interrompido. %n", nProdutor);  
         }  
     }
sergiotaborda

E são. O que significa “serem atendidos” significa : sair da fila e ir para um caixa. Não significa : sair do caixa para a rua na ordem que entrou no banco.

As threads retiram na ordem da fila, portanto está sendo atendido na ordem. A partir dai só Deus sabe.
Como vc colou a mensagem na thread a sua mensagem é equivalente a “temnado o atendimento ao cliente N” ou seja, vc está imprimindo a ordem em que o cliente sai do bando, não a ordem em que ele foi atendido.

A ordem de atendimento é definida pela Queue.

O ponto é o seguinte : a sua implementação está certa. É sua interpretação que está errada.

gugabarc

Pessoal, após a execução das threads eu tnho q guardar algumas informações… mas a threads do Caixa nao temrinam nunca, o que eu faço? Ja tentei o While(!Thread.interrupted()) mas nao funciona

sergiotaborda

A forma padrão é vc criar um atributo booleano que o while testa. Começa true e tem um método que o coloca em false.
Assim, vc chama thrread1.para(). e ela para.

Outra opção é usar um Executor que é uma classe que gerencia as threads para vc.

gugabarc

como podes ver nos codigos, eu utilizo executor, mas nada funciona, eu quero q ela encerrem o trabalho delas e deixem o resto do codigo correr

//Metodo que executará a tarefa da thread
	public void run() {
		try {
			//tempoInicial armazena o momento da execução do método
			long tempoInicial = System.currentTimeMillis();
    		        //Foi estabelecido que os caixas da agência atendem
			//por no máximo 60 segundos
			while (System.currentTimeMillis() - tempoInicial <= 60000) {
				System.out.println((System.currentTimeMillis() - tempoInicial)/1000);
				//Caixa atende o primeiro cliente da fila
				atendeCliente(filaClientes.take());
			}
		} catch (InterruptedException ex) {
			System.out.println(ex.getMessage());
		} finally {
			tempoMedioAtendimentoClientes = tempoMedioAtendimentoClientes/1000;
			quantidadeMediaRequisicoesPorCliente = totalRequisicoes / totalClientes;
			gravar();
		}
	}

=== CAIXA 4 ATENDENDO CLIENTE: 15 ===
11
=== CAIXA 1 ATENDENDO CLIENTE: 16 ===
13
=== CAIXA 2 ATENDENDO CLIENTE: 17 ===
13
=== CAIXA 3 ATENDENDO CLIENTE: 18 ===
14
=== CAIXA 2 ATENDENDO CLIENTE: 19 ===
15
15
17
17
20

ele para nos 20 segundos, enquanto deveria ir até 60… algo acontece com a thread q ela nao termina

Criado 14 de outubro de 2009
Ultima resposta 15 de out. de 2009
Respostas 17
Participantes 5