只有在条件为真且多线程时才应调用函数

时间:2013-03-16 03:23:27

标签: java multithreading concurrency

我遇到的问题是:在打印服务器的多线程模拟中,我需要做一些事情:

// in client
if (printer.isAvailable() && printer.isFair(this)) // is fair checks if its fair to allow client to print now
    printer.requestToPrint(something)
else
    printer.requestToPrintNext() // something like go into queue 

问题是:如果requestToPrintprinter.isAvailable() == false(即使在函数内),也不应调用printer.isFair(client) == false。我怎样才能确保这一点?简单的方法可能是将所有内容都包裹在synchronized (printer)中?但这意味着我将只有一个客户试图在任何时间打印,requestToPrintNext永远不会被调用?我该如何解决这个问题?

顺便说一句,所有这些功能都是在Interface中定义的,因此我认为我需要使用所有这些...

2 个答案:

答案 0 :(得分:2)

处理打印机的常用方法是在队列中组织打印作业,具有单一界面功能,如果打印机空闲则立即开始打印,否则将作业放入队列。如果提供的接口具有此功能,请使用它。如果没有,请创建自己的。如果打印是同步的,也就是说,直到所有打印都没有返回,请从单独的线程中调用它。

答案 1 :(得分:1)

从初看起来,您的客户似乎有太多的打印机逻辑。我认为客户端的方法更像是:

public void printMe() {
    printer.print(this);
}

打印机将处理所有可用的检查和排队和调度:

public synchronized boolean print(Client c, Something something) {
    if(isFair(c) && isAvailable()) {
        requestToPrint(something);
    }
    else {
        // queue
        // Not sure what "requestToPrintNext" does, 
        // as it has no argument, like "something"
    }
}

同步打印方法会阻止其他客户端相互跨越(下一个客户端将被阻塞,直到该方法为当前客户端完成)。正如其他海报所提到的,如果requestToPrint方法需要很长时间,你可以将其解析出来(只需确保它以某种方式将isAvailable设置为false,以便下一个客户端正确排队)。

上述print方法假设requestToPrint方法只是触发打印作业,阻止整个打印操作。示例实现可能类似于:

public void requestToPrint(Client c) {

    setAvailable(false);

    Thread job = new Thread(new Runnable() {
        @Override
        public void run() {

            // The actual print work

            setAvailable(true);
        }
    });

    job.start();
}

值得注意的是,此实现非常特定于此问题的约束。对于更通用的方法,单个打印队列(由其他答案引用)与单个工作线程为该队列提供服务将更加整洁。一个非常简单的骨架就是:

public void print(Client c) {
    synchronized(queue) {
        queue.add(c);
    }
}

public class PrintWorker implements Runnable {
    @Override
    public void run() {
        while(true) {
            Client c = null;
            synchronized(queue) {
                if(!queue.isEmpty()) {
                    c = queue.remove(0);
                }
            }

            if(c != null) {
                // do print work
            }
            else {
                // maybe add sleep or wait here
                // to keep thread from spinning
                // too fast and burning CPU
            }
        }
    }
}