Java中Semaphore的图书馆员资源分配问题

时间:2011-03-21 06:33:08

标签: java semaphore thread-synchronization

请帮我解决这个由两部分组成的问题。这是第一部分:

  

(第2部分:我已经更新了代码 - 需求已经改变了   位。)

我正在尝试用Java实现图书馆员问题。维基百科上的Semaphore page给出了图书馆对信号量的类比。在第一部分中,我试图模拟这个问题。在我的情况下,我使用[主题专家]而不是房间作为资源。

  

假设一个图书馆有10个相同的自习室,供一个学生一次使用。为了防止纠纷,学生如果想要使用自修室,必须要求前台的房间。当学生使用完房间后,学生必须返回柜台并指出一个房间已经空闲。如果没有免费的房间,学生们会在柜台等候,直到有人放弃房间。

     

由于房间相同,前台的图书管理员无法追踪占用的房间,只有免费房间的数量。当学生请求房间时,图书管理员会减少这个数字。当学生释放房间时,图书馆员会增加这个数字。一旦进入房间,房间可以根据需要使用,因此无法提前预订房间。

我在实施过程中遇到的问题是学生与学科专家的关联。您将如何在以下secnario中执行此操作? SubjectMatterExpert需要做的就是打印学生ID(暂时)。

  

第2部分:新要求:
    - 有固定数量的学生,中小企业和书柜     - 学生一开始就有一定数量的书籍(目前,书籍只是数字)
    - 中小企业应学生的要求在Boook Closet中添加或查看书籍     - 学生指定添加或签出操作,书籍数量和书架

这是经修改(编辑)的学生班级:

package librarysimulation;

public class Student extends Thread {

    String studentId = "";
    Librarian librarian = null;
    int bookCount = 0;

    public Student(String id, Librarian lib, int book) {
        studentId = id;
        librarian = lib;
        bookCount = book;
    }

    @Override
    public void run() {

        System.out.println("Student " + studentId + " is requesting SME...");
        librarian.requestSME();

        try {
            // Do something
            System.out.println("Student " + studentId + " has access to an SME.");
            //How do I ask the SME to add OR checkOut 'x' number of books
            //from a given BookCloset?
        } finally {
            librarian.releaseSME();
        }
    }
}

这是修改过的(编辑过的)图书馆员班级:

package librarysimulation;

import java.util.concurrent.Semaphore;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Librarian {

    public Semaphore sme;
    public int bookClosetCount = 0;

    public Librarian(int smeCount, int bookCloset) {
        sme = new Semaphore(smeCount, true);
        bookClosetCount = bookCloset;
        //openLibrary(smeCount);
    }

    //Receive SME request from the Student here
    public void requestSME() {
        try {
            sme.acquire();
            //assign student to SME
        } catch (InterruptedException ex) {
            Logger.getLogger(Librarian.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    //Release SME from the Student here
    public void releaseSME() {
        sme.release();//release SME
    }

    //Set the SME threads active (from constructor)
    //i.e., when the library opens, have the SMEs ready
    public final void openLibrary(int roomCount) {
        for (int i = 0; i < roomCount; i++) {
            SubjectMatterExpert s = new SubjectMatterExpert(String.valueOf(i));
            s.start();
        }
    }
}

这是经过修改(编辑)的主题事项专家课程:

package librarysimulation;

public class SubjectMatterExpert extends Thread {
    String smeId = "";
    SubjectMatterExpert(String id) {
        smeId = id;
    }

    @Override
    public void run(){

        //Handle Student request
        //Students specify if they are checking out books or returning books
        //Students specify number of books
        //Students specify which closet

        //SME simply executes the method from the Book Closet instance
    }
}

这是经过修改(编辑)的模拟器类:

package librarysimulation;

public class Simulator extends Thread {

    public static final int STUDENT_COUNT = 50;
    public static final int SME_COUNT = 3;
    public static final int BOOKCLOSET_COUNT = 10;
    public static final int BOOK_PER_STUDENT_COUNT = 10;

    @Override
    public void run() {
        //Instantiate Library//New library with 3 SMEs
        Librarian lib = new Librarian(SME_COUNT, BOOKCLOSET_COUNT);
        //Create students
        int i = 0;
        while (i < STUDENT_COUNT) {
            Student s = new Student(String.valueOf(i), lib, BOOK_PER_STUDENT_COUNT);
            s.start();
            i++;
        }
    }

    public static void main(String[] args) {
        Simulator s = new Simulator();
        s.start();
    }
}

这是(新)Book Closet类:

package librarysimulation;

public class BookCloset {

    int closetId;
    int bookCount = 0;

    public BookCloset(int id, int book) {
        closetId = id;
        bookCount = book;
    }

    public int addBook(int book){
        return bookCount + book;
    }

    public int checkOutBook(int book){
        int finalBookCount = bookCount - book;
        //Change book count iff it makes sense to do so
        if(finalBookCount >= 0)
            bookCount = finalBookCount;
        //If return value is -ve, handle accordingly
        return finalBookCount;
    }
}

2 个答案:

答案 0 :(得分:1)

在您描述的原始图书管理员问题中,问题并不关心哪个学生在哪个房间,因此使用简单的线程安全计数器(即信号量)来实现对资源的控制。根据对问题的描述,仍然需要更改您的实现。一种方法是在图书管理员班级中使用2种方法,一种用于请求SME,另一种用于返回。

class Librarian {
    Semaphore sme = new Semaphore(NUMBER_OF_SMES);

    void requestSme() throws InterruptedException {
        sme.acquire();
    }

    void releaseSme() {
        sme.release();
    }
}

 class Student {
     Librarian librarian;

     public void run() {

         libarian.requestSme();
         try {
             // Do something
         finally {
             librarian.releaseSme();
         }
     }
}

但是,如果您确实需要知道哪个学生正在使用哪个SME,那么您需要一个不同的构造来管理资源,信号量已不再足够。一个例子可能是队列。

class Librarian {
    BlockingQueue<SubjectMatterExpert> q = 
        new ArrayBlockingQueue<SubjectMatterExpert>(NUMBER_OF_SMES);

    public Librarian() {
        for (int i = 0; i < NUMBER_OF_SMES; i++)
            q.put(new SubjectMatterExpert(String.valueOf(i));
    } 

    SubjectMatterExport requestSme() throws InterruptedException {
        q.take();
    }

    void releaseSme(SubjectMatterExpert toRelease) {
        q.put(toRelease);
    }
}

 class Student {
     Librarian librarian;

     public void run() {

         SubjectMatterExpert sme = libarian.requestSme();
         try {
             System.out.println("Student: " + this + ", SME: " sme);
         finally {
             if (sme != null)
                 librarian.releaseSme(sme);
         }
     }
}

答案 1 :(得分:0)

将SME作为在while循环中运行的线程是有意义的。查看下面的一些起始代码。此外,您需要在模拟开始时的某处初始化书柜。我不知道你正在采取的整个方法。

package librarysimulation;

public class SubjectMatterExpert extends Thread {
    String smeId = "";
    SubjectMatterExpert(String id) {
        smeId = id;
    }

    @Override
    public void run(){

        while(true){
        //acquire a student (semaphor)
        //acquire a lock (semaphor(1))
             //critical region - 
             //Handle Student request
             //Students specify if they are checking out books or returning books
             //Students specify number of books
             //Students specify which closet
        //release yourself (semaphor - define in library)
        //release lock (semaphor(1)) 

        }
        //SME simply executes the method from the Book Closet instance
    }
}

在论坛中实施并仔细检查。我是新来的。更有经验的声音可能有更好的发言权。希望这有助于(=不会伤害)最终。