【问题标题】:how to achieve mutual exclusion using synchronized method in this application如何在此应用程序中使用同步方法实现互斥
【发布时间】:2013-03-19 18:57:04
【问题描述】:

我在这里遇到了一个小问题。我正在用 Java 做一个并发程序。问题是:有 4 个人(学生)试图访问打印机,打印 5 个文档。但当时只有一个可以打印(很明显)5 个文件。当他们完成时,他们通知其他人他们已经完成并且其他线程访问该资源。我有一个主类,学生类和监视器(激光打印机),文档类,其中包含有关文档的信息,例如(页数,名称用户 ID 等)+ 一些打印机接口。我已成功运行线程,但它们不同步(互斥)
所以问题是我如何实现互斥(当时只有一个人可以打印他的文档数量)
感谢您的关注、时间和提示 :)

主类

    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();

学生班

 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");

监控类

    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);

    }

【问题讨论】:

  • 你有什么问题?
  • @Keppil 抱歉忘了实际提问。发布更新
  • 看来您的监视器类扩展了另一个类。 printDocument 是否也在超类中同步?另外,为什么要在运行中创建一个新的打印机对象,而不是使用传递给 Student 类的那个?
  • 在学生课堂上,您使用的是本地 LaserPrinter,而不是使用共享对象 serviceprinter。如果你改变它,基于ServicePrinter 的printDocument 是同步的,我认为它可能会起作用。
  • @MaciejCygan 你应该在程序的某个点创建一个LaserPrinter 实例,就像主类一样,并通过Student 和TonerTechnician 的实例传递它,以便同步操作,如printDocument,一次只能由一个用户完成。明白了吗?

标签: java multithreading concurrency synchronization mutual-exclusion


【解决方案1】:

您似乎在 run 方法中创建了一个本地打印机对象,而不是使用您传递给 Student 类的共享打印机对象。尝试使用您传递的共享打印机,看看您会得到什么。我们还需要看看你如何在ServicePrinter 中使用printDocument。这是因为您在Student 类中使用了ServicePrinter 对象,而printDocument 在ServicePrinter 中的实现可能不正确(也就是说,如果您实际上在超类中实现了它)

【讨论】:

    【解决方案2】:

    这是一个简单的互斥锁实现,但您应该使用 java.util.concurrent 包进行同步

    编辑:将互斥量更改为信号量(更有意义)

    一个简单的互斥锁实现:

    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();            
            }
        }
    }
    

    【讨论】:

    • 你的类中互斥字段的意义何在? Object.wait() 和 Object.notify() 应该是创建互斥锁所需的全部内容。
    • @creechy - 你第一次获得锁怎么办。每个线程在调用 aquire() 时都会被阻塞
    • 哦,我明白了。我通常直接使用 wait() 和 notify(),有点让我失望。就像只是创建一个对象,然后使用 syncronized (object) { } 进行互斥。
    • 有两种方法(获取和释放)都是有意义的,但是当我有一种打印方法时。如何以一种方式获取和释放?
    猜你喜欢
    • 2015-08-09
    • 1970-01-01
    • 1970-01-01
    • 2016-06-21
    • 2017-12-08
    • 1970-01-01
    • 1970-01-01
    • 2021-03-28
    • 1970-01-01
    相关资源
    最近更新 更多