Librarian resource allocation in semaphore in Java
Please help me solve this two - Part problem This is the first part:
I'm trying to implement the libraian problem in Java The semaphore page on Wikipedia gives the library's analogy to semaphores In the first part, I try to simulate this problem In my case, I use [subject matter experts] instead of rooms as resources
The problem I encountered in the implementation is about the relationship between students and subject experts How would you do this in secnario below? What subject matter expert needs to do is print the student ID (now)
This is the revised (edited) student class:
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(); } } }
This is the revised (edited) librarian class:
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(); } } }
This is the modified (edited) subject matter expert class:
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 } }
This is the modified (edited) simulator class:
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(); } }
This is the (New) book close class:
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; } }
Solution
In the original librarian problem you described, the problem does not care which student is in which room, so a simple thread safe counter (i.e. semaphore) is used to control resources According to the description of the problem, you still need to change your implementation One method is to use two methods on the librarian class, one for requesting SME and the other for returning it
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(); } } }
However, if you really need to know which student is using which SME, you need a different construct to manage resources, and the semaphore is no longer sufficient An example might be a queue
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); } } }