3

Javaで次の問題を解決しようとしています:

喫煙者と禁煙者が通うバーがあります。バーには限られた数の顧客用の席があります。喫煙者と禁煙者が同時にバーにいることはできません。すべての顧客はバーに移動するのに時間を費やし、バーに入ってしばらく過ごし、最後に立ち去り、他の顧客が入るのを待っています。喫煙している顧客がバーを離れた後、内部の空気をリフレッシュする必要があります禁煙のお客様が来られるように。

Java のスレッド同期メソッドを使用してこの問題の簡単なシミュレーションを作成し、デッドロックが発生しないことを確認してください。

私が思いついたのは、次のコードでした。ただし、問題が 1 つあります。空気をリフレッシュするために必要な時間、バーをロックする必要があるという条件を実装するにはどうすればよいですか?

これはコードです:

class Bar {
    int maxP;
    int curP;
    String state;

    public Bar(int maxP) {
        this.maxP = maxP;
        curP = 0;
        state = "none";
    }
    public synchronized void enterBar(Customer customer) {
        if(state == "none") {
            state = customer.smokingStatus;
        }
        while((curP == maxP) || state != customer.smokingStatus) {
            System.out.println(customer.name+" " + customer.smokingStatus + " is waiting to enter the bar. ");
            try {
                wait();
                if(curP == 0 && state == "none") {
                    state = customer.smokingStatus;
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        curP++;
        System.out.println(customer.name +" "+ customer.smokingStatus + " enters the bar and relaxes. ");

    }
    public synchronized void leaveBar(Customer customer) {
        curP--;
        if(curP == 0) {
                 state = "none";
             }
        System.out.println(customer.name +" " + customer.smokingStatus + " stops relaxing and leaves the bar.");
        notifyAll();
    }
}

次に、顧客をクラス化します。

class Customer extends Thread {
    String name;
    String smokingStatus;
    Bar bar;

    public Customer(String name, String smoker, Bar bar) {
        this.name = name;
        this.smokingStatus = smoker;
        this.bar = bar;
    }
    public void run() {
        System.out.println(this.name + " is traveling to the bar.");
        try {
            sleep((int)(Math.random()*1000));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        bar.enterBar(this);
        try {
            sleep((int)(Math.random()*5000));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        if (this.smokingStatus.equals("smoker")){
            System.out.println("After I've been here the bar's air needs some refreshing.");
            try {
                sleep((int)(Math.random()*2000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        bar.leaveBar(this);
    }
}

そして最後に main() メソッド:

class MainApp {
    public static void main(String args[]) {
        Bar s = new Bar(5);
        for(int i = 0; i < 10; i++) {
            String smokingStatus;
            smokingStatus = Math.random() > 0.5 ? "smoker" : "nonsmoker";
            (new Customer("Customer " + i, smokingStatus, s)).start();
        }
    }
}

空気をリフレッシュするためにバーをロックするにはどうすればよいですか?

4

2 に答える 2

2

橋の上の赤と青の車に関する Magee & Kramer の例の修正版を作成しました。ここを参照してください ( http://flylib.com/books/en/2.752.1.48/1/ )。TIME_TO_CLEAR_AIR と MAX_PATRONS のものを追加しました。あなたが望むものにかなり近いはずです。変数の名前を適切に変更します。顧客のタイプに応じて、適切な開始/終了メソッドを呼び出します。

public class SafeBar {

 // smokers in the bar
 private int smokers = 0; 

 private int MAX_PATRONS = 20;

 // non-smokers in the bar
 private int nonSmokers = 0; 

 // last time a smoker left the bar
 private long lastSmoke = 0;
 private long TIME_TO_CLEAR_AIR = 10000; // 10 seconds

 synchronized void smokerEnter() throws InterruptedException { 

    while (nonSmokers>0||smokers==MAX_PATRONS) { 
        wait();
    }

    ++smokers; 
 } 

 synchronized void smokerExit(){ 
    --smokers; 
    if (smokers==0) lastSmoke = new Date().getTime();
    notifyAll(); 
 } 

 synchronized void nonSmokerEnter() throws InterruptedException { 

    long checkTime = 0;
    while (smokers>0||nonSmokers==MAX_PATRONS||(checkTime = new Date().getTime()) - lastSmoke < TIME_TO_CLEAR_AIR) {
        if (checkTime - lastSmoke < TIME_TO_CLEAR_AIR)
            wait(TIME_TO_CLEAR_AIR - (checkTime - lastSmoke));
        else 
            wait(); 
    }

    ++nonSmokers; 
 } 

 synchronized void nonSmokerExit(){ 
    --nonSmokers; 
    notifyAll(); 
 } 
}
于 2012-11-30T23:20:38.347 に答える
1

このleaveBar(Customer)方法では、バーを離れた顧客が喫煙者で最後の 1 人である場合、しばらく (リフレッシュする時間) スリープする新しいスレッドを開始し、最後に空気が新鮮であることをバーに伝えます。空気がきれいになったら、電話notifyAll()して次の顧客をバーに入れます。

于 2012-11-30T21:48:18.690 に答える