一見したところ、クライアントにはプリンター ロジックが多すぎるように見えます。クライアントには次のような方法があると思います。
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
}
}
}
}