0

i have run into a little problem in here. I am doing a concurrent program in Java. Problem is: There are 4 people (students) that are trying to access printer, to print 5 documents. But only one can print at the time (kind of obvious) 5 documents. When they finish they notify other that they done and other thread accesses the resource. i have a Main class, student class and Monitor (laser printer), Document class that holds info about the document like (number of pages, name user id etc)+ few interfaces for printer. I have managed to run successfully threads but they are not synchronized (mutual exclusion)
So the question is how do i achieve mutual exclusion ( that only one person can print at the time his number of docs)
Thank you for looking, time and hints :)

Main class

    String S1Name = "bob";
    String S2Name = "klara";
    String S3Name = "John";
    String S4Name = "Iga";

    String T1Name = "Man";
    String T2Name = "Woman";


    final int NoOfDocs = 5;
    ServicePrinter sp = new LaserPrinter();

    ThreadGroup groupA = new ThreadGroup("Group A"); 
    ThreadGroup groupB = new ThreadGroup("Group B");

    Student student1 = new Student(sp,NoOfDocs,S1Name, groupA);
    Student student2 = new Student(sp,NoOfDocs,S2Name, groupA);
    Student student3 = new Student(sp,NoOfDocs,S3Name, groupA);
    Student student4 = new Student(sp,NoOfDocs,S4Name, groupA);

    TonerTechnician TT = new TonerTechnician(groupB);
    PaperTechnician PT = new PaperTechnician(groupB);

    /*
     * Start Student Threads
     */
    student1.start();
    student2.start();
    student3.start();
    student4.start();

    /*
     * Start Technician threads
     */
    TT.start();
    PT.start();

Student Class

 private final ServicePrinter serviceprinter;
    private final int NoOfDocs;
    private final String Name;
    private final ThreadGroup threadgroup;

    public Student(ServicePrinter serviceprinter, int NoOfDocs, String Name, ThreadGroup threadgroup)
    {
        this.serviceprinter = serviceprinter;
        this.NoOfDocs = NoOfDocs; 
        this.Name = Name;
        this.threadgroup = threadgroup;
    }
    @Override
    public void run()
    {
        /*
         * each students prints 5 documents (different name and length)
         */
        final LaserPrinter lp = new LaserPrinter();
        //sleep from 1 to 5 sec random time
        final Random random = new Random();       
        char[] chars = "abcdefghijklmnopqrstuvwxyz".toCharArray();
        StringBuilder sb = new StringBuilder();
        /*
         * Create random document name 10 characters long
         */
        for (int i = 0; i < 10; i++) 
        {
            char c = chars[random.nextInt(chars.length)];
            sb.append(c);
        }
        String docName  = sb.toString();
        /*
         * print 5 documents (random sleep time between printing)
         */
        for(int i = 0; i < NoOfDocs; i++)
        {
            try 
            {
                Document coursework = new Document(Name,docName,random.nextInt(90)+10);
                lp.printDocument(coursework);
                Thread.sleep(random.nextInt(1000)+4000);                
            } 
            catch (InterruptedException ex) 
            {
                Logger.getLogger(Student.class.getName()).log(Level.SEVERE, null, ex);
            }            
        }
        System.out.println("User: " + Name+ " completed printing");

Monitor class

    int tonerLevel = 500;
    int paperLevel = 250;

    private final String PrinterName = "HP";
    private final String PrinterID = "LX-440";
    private int CurrentPaperLevel;
    private int CurrentTonerLevel;
    private int NoOfDocsPrinted;

    @Override
    public synchronized void printDocument(Document document) {
        System.out.println(document);

    }
Maciej Cygan
  • 5,351
  • 5
  • 38
  • 72
  • 1
    What is your question? – Keppil Mar 19 '13 at 18:59
  • @Keppil sorry forgot to actually ask the questions. Post updated – Maciej Cygan Mar 19 '13 at 19:01
  • Well it seems your monitor class extends another class. Is printDocument synchronized in the superclass as well? Also why are you creating a new printer object in run instead of using the one you pass to the Student class? – Kakalokia Mar 19 '13 at 19:03
  • At Student class you are using a local `LaserPrinter` instead of using the shared object `serviceprinter`. If you change that, base on that `printDocument` of `ServicePrinter` is synchronized I think it might work. – Jose Renato Mar 19 '13 at 19:05
  • You have 5 printers which can be used at the same time. (`final LaserPrinter lp = new LaserPrinter();` in your run method) – assylias Mar 19 '13 at 19:07
  • @AliAlamiri printDocument is a method in Interface Printer (not synchronized). the reason why i create new object is because threads need to communicate data through the shared laserprinter object – Maciej Cygan Mar 19 '13 at 19:15
  • @assylias i dont have 5 printers that can be used. i am printing 5 documents – Maciej Cygan Mar 19 '13 at 19:19
  • But have you tried using the shared printer? and why are you not declaring the method as synchronized in the interface but implementing it as synchronized? – Kakalokia Mar 19 '13 at 19:20
  • @JoseRenato serviceprinter is a interface that technicians will use later on. This one does not apply to Student class – Maciej Cygan Mar 19 '13 at 19:20
  • @MaciejCygan ok. But considering that `printDocument` is synchronized, if you use a shared instance of `LaserPrinter`, it will be guaranteed that the printing of a document is atomic. – Jose Renato Mar 19 '13 at 19:47
  • @JoseRenato I am kinda lost, where should i use the laserprinter instance ? – Maciej Cygan Mar 19 '13 at 20:26
  • @MaciejCygan still you create 4 printers in your code, one per student. – assylias Mar 19 '13 at 20:56
  • @assylias i just removed the code in question, but still getting the same result. In fact this code did not make any difference – Maciej Cygan Mar 19 '13 at 21:52
  • 1
    @MaciejCygan you should create a `LaserPrinter` instance at some point of the program, like the main class, and pass it through the instances of `Student` and `TonerTechnician`, so that the synchronized operations, like `printDocument`, can be done by only one user at time. Got it? – Jose Renato Mar 21 '13 at 17:38
  • @JoseRenato yup got it now, it seems to all work :) – Maciej Cygan Mar 22 '13 at 01:00

2 Answers2

0

Here is a simple mutex implementation but you should use java.util.concurrent package for synchronization

EDIT: Changed mutex to semaphore (it makes more sense)

A simple mutex implementaion:

public class Mutex {

    private int semaphore;

    public synchronized void aquire() throws InterruptedException {

        if(semaphore < 0) {
            wait();
        }

        semaphore--;

    }

    public synchronized void release() {

        if(semaphore < 0) {
            semaphore++;
            notify();            
        }
    }
}
emd
  • 740
  • 4
  • 12
  • What is the point of the mutex field in your class? Object.wait() and Object.notify() should be all you need to create a mutex. – creechy Mar 19 '13 at 22:01
  • @creechy - how else would you aquire a lock for the first time. Each thread would be blocked when he calls aquire() – emd Mar 19 '13 at 22:05
  • Oh right I see. I generally use wait() and notify() directly, kind of threw me off. Like just creating an object and then use syncronized (object) { } for mutual exclusion. – creechy Mar 19 '13 at 22:15
  • it all makes sense having two methods (acquiring and releasing) but when i have one method for printing. How do i acquire and release in one method ? – Maciej Cygan Mar 19 '13 at 22:52
0

It seems that you're creating a local printer object in your run method instead of using the shared one you pass to the Student class. Try using the shared printer that you pass and see what you get. Also we need to see how you use printDocument in ServicePrinter. This is because you are using a ServicePrinter object in your Student class, and the implementation of printDocument in ServicePrinter may not be correct (that is if you actually have it implemented in the superclass)

Kakalokia
  • 3,191
  • 3
  • 24
  • 42