Java - 线程问题

时间:2011-06-22 14:08:42

标签: java multithreading thread-safety

我有一个班级Producer和一个班级Printer。 生产者从文件数据中读取以创建PrinttJobs个对象。 Producer生成一个PrintJob并添加到Queue,通知PrinterProducer比等待1到5秒创建新的PrintJobs。 当Printer未通过时,它会打开并从队列中获取作业并打印它们。在此期间Producer无效。 Printer打印所有内容并再次等待,让Producer再次运行。 该应用程序适用于2个生产者和1个打印机。 我的问题是,有时它会顺利进行,有时它不会打印产生一切。另外我认为我的wait时间限制为1-5秒不能正常工作/可能是问题所在。代码如下:

EDITED

当制作人实际制作某些东西时,他们几乎总是在同一时间发送。有时它会停止生成文件中的数据。

class Printer implements Runnable {

    protected long MILLIS_PER_PAGE = 500;

    private String name;
    Queue queue;
    boolean lock = false;

    public Printer(String name, Queue queue) {
        this.name = name;
        this.queue = queue;
    }

    public String getPrinterName() {
        return name;
    }

    @Override
    public void run() {
        System.out.println("["+getPrinterName()+"] Ligando...");
        while(true) {
            synchronized(this){
                if(queue.isEmpty()) {
                    try {
                        System.out.println("["+getPrinterName()+"] Esperando por tabalho de impressão...");
                        lock = false;
                        halt();
                    } 
                    catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                }
                else {
                    lock = true;
                    PrintJob pj = queue.removeFront();
                    System.out.println("Imprimindo "+ pj.getJobName());
                    try {
                        wait(pj.getNumberOfPages() * MILLIS_PER_PAGE);
                        System.out.println(pj.getJobName() + " ok.");
                    } 
                    catch (InterruptedException e) {
                        e.printStackTrace();
                    }


                }
            }
        }
    }

    public void halt() throws InterruptedException {

        wait();

    }

}
`

`
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Scanner;

class Producer implements Runnable {

    private String name;
    Queue queue;

    String job;
    int pags;
    String arquivo;

    public Producer(String name, Queue queue, String arquivo) {
        this.name = name;
        this.queue = queue;
        this.arquivo = arquivo;
    }

    public String getProducerName() {
        return name;
    }

    @Override
    public void run(){
        synchronized (PrinterApp.printer) {

            FileReader fin;

            try {
                fin = new FileReader(arquivo);
                Scanner src = new Scanner(fin);

                while (src.hasNext() ) {
                    if (PrinterApp.printer.lock == true){
                        PrinterApp.printer.wait();
                    }
                    job = src.next();
                    pags = src.nextInt();
                    PrintJob p = new PrintJob(job, pags);

                    queue.addBack(p);

                    System.out.println("["+getProducerName()+"] produzindo arquivo " + job +", número de páginas: " + pags);
                    PrinterApp.printer.notify();
                    PrinterApp.printer.wait(1000 + (int)Math.round((Math.random() * (5000 - 1000))));  

                }
                fin.close();
            }


            catch (FileNotFoundException e) {
                e.printStackTrace();

            } 
            catch (QueueException e) {

                e.printStackTrace();
            }

            catch (IOException e) {
                e.printStackTrace();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

        }
    }
}

1 个答案:

答案 0 :(得分:3)

问题在于以下

                if (PrinterApp.printer.lock == true){
                    PrinterApp.printer.wait();
                }
等待结束后

锁定可能不正确。等待应始终处于循环中。

此外,打印机从不通知生产者锁已更改。你应该在打印机中调用wait之前调用notify。

如果这不是作业,那么我建议使用阻止队列来处理所有等待并通知你。

class Printer implements Runnable {

protected long MILLIS_PER_PAGE = 500;

private String name;
Queue queue;
boolean lock = false;

public Printer(String name, Queue queue) {
    this.name = name;
    this.queue = queue;
}

public String getPrinterName() {
    return name;
}

@Override
public void run() {
    System.out.println("["+getPrinterName()+"] Ligando...");
    while(true) {
        synchronized(this){
            if(queue.isEmpty()) {
                try {
                    System.out.println("["+getPrinterName()+"] Esperando por tabalho de impressão...");
                    lock = false;
                    notifyAll();
                    halt();
                } 
                catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
            else {
                lock = true;
                PrintJob pj = queue.removeFront();
                System.out.println("Imprimindo "+ pj.getJobName());
                try {
                    wait(pj.getNumberOfPages() * MILLIS_PER_PAGE);
                    System.out.println(pj.getJobName() + " ok.");
                } 
                catch (InterruptedException e) {
                    e.printStackTrace();
                }


            }
        }
    }
}

public void halt() throws InterruptedException {

    wait();

}

}
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Scanner;

class Producer implements Runnable {

private String name;
Queue queue;

String job;
int pags;
String arquivo;

public Producer(String name, Queue queue, String arquivo) {
    this.name = name;
    this.queue = queue;
    this.arquivo = arquivo;
}

public String getProducerName() {
    return name;
}

@Override
public void run(){
    FileReader fin;

    try {
         fin = new FileReader(arquivo);
         Scanner src = new Scanner(fin);

         while (src.hasNext() ) {                    
         synchronized (PrinterApp.printer) {
                while (PrinterApp.printer.lock == true){
                    PrinterApp.printer.wait();
                }
                job = src.next();
                pags = src.nextInt();
                PrintJob p = new PrintJob(job, pags);

                queue.addBack(p);

                System.out.println("["+getProducerName()+"] produzindo arquivo " + job +", número de páginas: " + pags);
                PrinterApp.printer.notifyAll();
             }
             // don't wait here since your not waiting on a condition to change
             Thread.sleep(1000 + (int)Math.round((Math.random() * (5000 - 1000))));  

            }
            fin.close();
        }


        catch (FileNotFoundException e) {
            e.printStackTrace();

        } 
        catch (QueueException e) {

            e.printStackTrace();
        }

        catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
}
}