I'm trying to simulate a printer setup in which monochrome and colour prints are done sequentially. When removing a print statement, my code produces unexpected results.
The function in question is request(). I have researched this and came across lots of articles where it is discussed that this revolves around thread synchronization and adding the synchronization keyword to the function, or to make the variable in question volatile.
I believe that my three threads are simultaneously popping the list and retrieving the same data as the output WITHOUT printouts is:
(0) M3 uses head 1 (time: 3)
(0) M3 uses head 2 (time: 3)
(0) M3 uses head 3 (time: 3)
Where as including the printouts is:
grabbed job M1
grabbed job M2
(0) M1 uses head 1 (time: 4)
grabbed job M3
(0) M2 uses head 2 (time: 5)
(0) M3 uses head 3 (time: 3)
However, I have from the beginning of this project had the synchronized keyword in my function. I also have tried replacing the keyword with a binary semaphore within the function. This article was found to be informative, but not an answer to my exact scenario: Questions about thread+loop not working without print statement
My code:
import java.util.LinkedList;
public class Printer{
public static int TIME = 0;
private static boolean COLOURMODE = true;
private static LinkedList<Job> jobs;
private static Job tempJob;
private PrinterHead printHead1;
private PrinterHead printHead2;
private PrinterHead printHead3;
public Printer(LinkedList<Job> jobs) {
this.jobs = jobs;
printHead1 = new PrinterHead(this,1);
printHead2 = new PrinterHead(this,2);
printHead3 = new PrinterHead(this,3);
printHead1.start();
printHead2.start();
printHead3.start();
}
public static boolean hasJobs(){
if(jobs.isEmpty()){
return false;
}
else{
return true;
}
}
public synchronized Job request(){
tempJob = jobs.peek();
if(COLOURMODE){
if(tempJob.type == 'C'){
//System.out.println("grabbed job " + tempJob.jID);
return jobs.pop();
}
else{
COLOURMODE = false;
printHead1.TIME = TIME;
printHead2.TIME = TIME;
printHead3.TIME = TIME;
}
}
else if(!COLOURMODE){
if(tempJob.type == 'M'){
//System.out.println("grabbed job " + tempJob.jID);
return jobs.pop();
}
else{
COLOURMODE = true;
printHead1.TIME = TIME;
printHead2.TIME = TIME;
printHead3.TIME = TIME;
}
}
return null;
}
}
edit: PrinterHead class added.
import java.util.concurrent.Semaphore;
public class PrinterHead extends Thread {
private static Job job;
public static int TIME = 0;
private int headNum;
private static Printer printer;
private static Semaphore mutex = new Semaphore(1, true);
public PrinterHead(Printer printer, int headNum){
this.headNum = headNum;
this.printer = printer;
}
public void run(){
while(printer.hasJobs()){
job = printer.request();
if (job != null){
print();
if(printer.TIME < job.pages+TIME){
printer.TIME = job.pages+TIME;
}
try{
this.sleep(1000*job.pages);
}
catch(Exception e){
System.out.println("some shit broke in printhead " + headNum);
return;
}
}
}
}
private void print(){
try{
mutex.acquire();
System.out.println("("+TIME+") "+ job.jID+" uses head "+headNum + " (time: "+job.pages+")");
mutex.release();
}
catch(Exception e){
System.out.println("some shit broke in printout " + headNum);
return;
}
}
}
My Main
creates one Printer
instance and a LinkedList
of Job
s.
If you need more, ask me please and thank you.