Duvida com wait() e notify()

4 respostas
E

Olá a todos, estou tentando fazer uma pequena simulação de Fila de Impressão, se é que posso colocar dessa forma, e estou tendo um pequeno problema nesta parte final:

Na classe Printer, enquanto a fila de impressão estiver vazia, a impressora fica em espera, logo, quando estiver com algum arquivo, ela simplesmente da um println avisando que está imprimindo o arquivo.

Na classe Producer, ele monitora o que a impressora está fazendo, se ela estiver imprimindo algo, a Producer entra em espera, caso contrario, ela envia um arquivo para a fila de impressão, o que aciona a Printer novamente e assim sucessivamente.

Porém, como nunca utilizei os métodos wait() e notify(), estou tendo um pequeno problema com eles, e gostaria de saber a opinião de vocês a respeito do que eu posso fazer para corrigir este problema:

Classe Printer

public class Printer extends Thread {

    long MILLIS_PER_PAGE = 500;
    String nome;
    CircularQueue queue;
    Producer p;

    public Printer(String name, CircularQueue cq) {
        queue = cq;
        nome = name;
        System.out.println("[" + nome + "]: Ligando");
    }

    public synchronized void run() {
        try {
            while (true) {
                //
                while (queue.isEmpty()) {
                    System.out.println("[" + nome + "]: Esperando por trabalho de impressão...");
                    wait();
                }
                System.out.println("Imprimindo...");
                Thread.sleep(MILLIS_PER_PAGE);
                //
            }
        } catch (InterruptedException ex) {
            System.out.println("Erro: " + ex);
        }
    }

    public String getPrinterName() {
        return nome;
    }

    public void halt() {
    }
}

Classe Producer

import java.io.*;

public class Producer extends Thread {

    String nome;
    String file;
    String split[];
    CircularQueue queue;


    /*Alterado a assinatura do metodo Producer para facilitar a manipulação de arquivos de texto*/
    public Producer(String name, String arquivo, CircularQueue cq) {
        nome = name;
        file = arquivo;
        queue = cq;
    }

    public Producer(String name, String arquivo) {
        nome = name;
        file = arquivo;
    }

    public String getProducerName() {
        return nome;
    }

    public synchronized void run() {
        try {
            BufferedReader leitor = new BufferedReader(new FileReader(file));
            String linha = leitor.readLine();
            while (linha != null) {
                while (!queue.isEmpty()) {
                    notify();
                }
                //processar a linha lida
                split = linha.split("-");//divide o nome do arquivo do numero de paginas
                /*Cria PrintJob*/
                PrintJob pj = new PrintJob(split[0], Integer.parseInt(split[1])); //Cria um novo PrintJob
                queue.addBack(pj);//adiciona PrintJob na Fila 
                /*Fim Criacao*/
                System.out.println("#" + nome + "#: produzindo arquivo '" + split[0] + "', número de páginas " + split[1]);//Saida dos Producers
                linha = leitor.readLine();//lê a proxima linha
                Thread.sleep((int) (1 + (Math.random() * 5)) * 1000);//Tempo randomico entre 1 e 5 segundos para enviar um arquivo a Fila de Impressao
            }
            leitor.close();//fecha obj de leitura
            System.out.println("Numero de Jobs: " + queue.getNumberOfJobs());
        } catch (InterruptedException ex) {
            System.out.println("Erro " + ex);//Falha de Sleep
        } catch (FileNotFoundException ex) {
            System.out.println("Erro " + ex);//Arquivo nao encontrado
        } catch (IOException ex) {
            System.out.println("Erro " + ex);//Erro na Leitura
        }
    }
}

Classe Main

public class PrinterApp {

    public static void main(String[] args) throws Exception {
        CircularQueue cq = new CircularQueue();
        new Producer("Producer1", "arquivos_impressao.txt", cq).start();
        new Printer("Printer",cq).start();
    }
}

Agradeço antecipadamente qualquer ajuda.

Abraços,
Enrico

4 Respostas

soaresinfo

Todos os objetos possuem o wait e notify, independente de ser thread ou não. Tendo isso esclarecido, o que você fez foi chamar o wait do objeto Printer, a thread dele parou, blz, mas quando você chama o notify, está chamando do objeto Producer, e este objeto não estava no wait e sim o seu Printer. Portanto para acordar o printer, o seu producer deveria ter feito

printer.notify();

quando instanciar o Producer, passe a referencia do printer para ele, assim você poderá chamar o notify do objeto corretamente.

E

Entendi o que você quis dizer, mas ainda sim me deu um pequeno problema. Como eu passo a Printer no main, estou tratando a referencia desse modo na classe Producer:

Printer printer;

    public Producer(String name, String arquivo, CircularQueue cq, Printer p) {
        nome = name;
        file = arquivo;
        queue = cq;
        printer = p;
    }
    //mais codigo
       printer.notify(); //dentro do metodo run

Porém ele dispara uma IllegalMonitorStateException pelo fato de eu estar chamando um notify fora de um contexto synchronized. Algo que eu possa fazer?

Uma outra pergunta, essa sua resposta foi para “acordar” a printer, quando eu precisar deixar a printer em wait, e acordar o Producer tenho que fazer a mesma coisa? Passar uma referencia de Producer para Printer?

Abraços,
Enrico

soaresinfo

faça assim:

synchronized(printer){
   printer.notify();
}

enrico28101991:
Uma outra pergunta, essa sua resposta foi para “acordar” a printer, quando eu precisar deixar a printer em wait, e acordar o Producer tenho que fazer a mesma coisa? Passar uma referencia de Producer para Printer?

Sim, mas atente-se para não deixar os dois objetos em wait, senão, nunca sairão desse estado.

E

permaneceu da mesma maneira, tentei varias combinações diferentes, parece que não consigo acordar a classe Printer. O código está desta maneira por enquanto, será que você poderia me dar uma luz a mais?

Printer:

package br.com.lab360.teste;

public class Printer extends Thread {

    long MILLIS_PER_PAGE = 500;
    String nome;
    CircularQueue queue;
    Producer p;

    public Printer(String name, CircularQueue cq) {
        queue = cq;
        nome = name;
        System.out.println("[" + nome + "]: Ligando");
    }

    public synchronized void run() {
        try {
            while (true) {
                if (queue.isEmpty()) {
                    System.out.println("[" + getPrinterName() + "]: Esperando por trabalho de impressão...");
                    wait();
                } else {
                    /*
                    if(!queue.isEmpty()) {
                    Thread.sleep(MILLIS_PER_PAGE);
                    }*/
                    System.out.println("[" + getPrinterName() + "]: Imprimindo...");
                }
            }
        } catch (Exception ex) {
            System.out.println("Erro: " + ex);
        }
    }

    public String getPrinterName() {
        return nome;
    }

    public void halt() {
    }
}
package br.com.lab360.teste;

import java.io.*;

public class Producer extends Thread {

    String nome;
    String file;
    String split[];
    CircularQueue queue;
    Printer printer;


    /*Alterado a assinatura do metodo Producer para facilitar a manipulação de arquivos de texto*/
    public Producer(String name, String arquivo, CircularQueue cq, Printer p) {
        nome = name;
        file = arquivo;
        queue = cq;
        printer = p;
    }

    public Producer(String name, String arquivo) {
        nome = name;
        file = arquivo;
    }

    public String getProducerName() {
        return nome;
    }

    @Override
    public synchronized void run() {
        synchronized (printer) {
            try {
                BufferedReader leitor = new BufferedReader(new FileReader(file));
                String linha = leitor.readLine();
                while (linha != null) {
                    if (queue.isEmpty()) {
                        //processar a linha lida
                        split = linha.split("-");//divide o nome do arquivo do numero de paginas
                        /*Cria PrintJob*/
                        PrintJob pj = new PrintJob(split[0], Integer.parseInt(split[1])); //Cria um novo PrintJob
                        queue.addBack(pj);//adiciona PrintJob na Fila 
                        /*Fim Criacao*/
                        System.out.println("#" + getProducerName() + "#: produzindo arquivo '" + split[0] + "', número de páginas " + split[1]);//Saida dos Producers
                        System.out.println("Numero de JOBS: " + queue.getNumberOfJobs());
                        linha = leitor.readLine();//lê a proxima linha
                        //wait();
                    }else{
                        System.out.println("fila com JOB...");
                        printer.notify();
                        wait();
                    }
                    Thread.sleep((int) (1 + (Math.random() * 5)) * 1000);//Tempo randomico entre 1 e 5 segundos para enviar um arquivo a Fila de Impressao
                }
                leitor.close();//fecha obj de leitura
                System.out.println("Numero de Jobs: " + queue.getNumberOfJobs());
            } catch (InterruptedException ex) {
                System.out.println("Erro " + ex);//Falha de Sleep
            } catch (FileNotFoundException ex) {
                System.out.println("Erro " + ex);//Arquivo nao encontrado
            } catch (IOException ex) {
                System.out.println("Erro " + ex);//Erro na Leitura
            }
        }
    }
}

Classe Main:

package br.com.lab360.teste;

public class PrinterApp {

    public static void main(String[] args) throws Exception {
        CircularQueue cq = new CircularQueue();
        Printer p =  new Printer("Printer",cq);
        p.start();
        Producer p1 = new Producer("Producer1", "arquivos_impressao.txt", cq, p);
        p1.start();
        //Producer p2 = new Producer("Producer2", "arquivos_impressao2.txt", cq);
        //p2.start();
    }
}

Agradeço antecipadamente,

Abraços.

Criado 16 de junho de 2011
Ultima resposta 17 de jun. de 2011
Respostas 4
Participantes 2