4

この 2 部構成の質問について教えてください。最初の部分は次のとおりです。

(パート 2: コードを更新しました - 要件が少し変更されました。)

Java でライブラリアンの問題を実装しようとしています。ウィキペディアのセマフォのページでは、セマフォのライブラリのアナロジーが提供されています。最初の部分では、この問題をモデル化しようとしています。私の場合、ルームの代わりに [対象分野の専門家] をリソースとして使用しています。

図書館に 10 室の同一の自習室があり、一度に 1 人の学生が使用することを想定しているとします。学生が自習室を利用したい場合は、紛争を防ぐためにフロントカウンターから部屋をリクエストする必要があります。部屋の使用が終わったら、学生はカウンターに戻り、1 つの部屋が空いたことを示さなければなりません。空いている部屋がない場合、学生は誰かが部屋を放棄するまでカウンターで待ちます。

部屋は同一であるため、フロント デスクの司書はどの部屋が使用されているかを把握しておらず、空いている部屋の数のみを把握しています。学生が部屋をリクエストすると、司書はこの数を減らします。学生が部屋を解放すると、司書はこの数を増やします。部屋へのアクセスが許可されると、その部屋は必要な期間使用できるため、事前に部屋を予約することはできません。

私の実装で直面している問題は、学生と主題の専門家との関連付けに関するものです。次のシナリオでこれをどのように行いますか? SubjectMatterExpert学生証を印刷するだけです(今のところ)。

パート 2: 新しい要件:
- 学生、SME、ブック クローゼットの固定数があります
- 学生は最初に特定の数の本を持っています (現在、本は単なる数字です)
- SME はブック クローゼットから本を追加またはチェックアウトします。生徒のリクエスト
- 生徒は追加またはチェックアウト アクション、本の数、ブック クローゼットを指定します

これは変更 (編集) された Student クラスです。

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

これは、修正 (編集) された Subject Matter Expert クラスです。

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
    }
}

これは、変更 (編集) された Simulator クラスです。

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;
    }
}
4

2 に答える 2

1

あなたが説明した元の図書館員の問題では、問題はどの学生がどの部屋にいるかを気にしないため、単純なスレッドセーフカウンター(つまりセマフォ)を使用してリソースの制御を実装します。問題の説明に続いて、実装を変更する必要があります。1 つのアプローチは、ライブラリアン クラスで 2 つのメソッドを使用することです。1 つは SME を要求するためのもので、もう 1 つはそれを返すためのものです。

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

ただし、どの Student がどの SME と作業しているかを知る必要がある場合は、リソースを管理するための別の構造が必要になります。セマフォではもはや十分ではありません。1 つの例として、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);
         }
     }
}
于 2011-03-21T14:51:18.810 に答える
0

while ループで実行されるスレッドとして SME を使用することは理にかなっています。以下のいくつかの開始コードを確認してください。また、シミュレーションの開始時にブック クローゼットをどこかで初期化する必要があります。私はあなたがとっているアプローチ全体について知りません。

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
    }
}

実装し、フォーラムで他のユーザーと再確認してください。私はここでは新人です。ただし、より経験豊富な声の方がより良い発言をする可能性があります。これが最後に役立つことを願っています (= 害はありません)。

于 2011-03-23T02:07:26.773 に答える