解答例 - 実習課題2 - 5.スレッドの同期
(実習課題2)
2節のサンプルプログラムを、簡単な待ち行列をシミュレーションするプログラムに改良しなさい。ATMの数を1つ2つと変化させて、シミュレーションを実行しなさい。
- 待ち行列の長さに上限は無い。つまり待ち行列が一杯なので、待機するという事は無い。
- 顧客は、平均して3秒に1人到着する。到着間隔は、ポアソン分布に従うのが理想だが、どのようなものでも構わない。
- ATMは、平均して2秒で1人分のサービスを完了する。サービス時間は、指数分布に従うのが理想だが、どのようなものでも構わない。
解答例
/**
* QueueTest.java
* TECHSCORE Java マルチスレッドプログラミング5章 実習課題2
*
* ATMの処理時間、顧客の到着間隔ともに一様分布を利用
*
* Copyright (c) 2004 Four-Dimensional Data, Inc.
*/
package com.techscore.thread.chapter5.exercise2;
import java.util.LinkedList;
import java.util.Iterator;
public class QueueTest {
public static void main(String[] args) throws Exception {
Queue queue = new Queue();
//1台目のATM[A]
Atm atmA = new Atm(queue, "A");
//2台目のATM[B]
Atm atmB = new Atm(queue, "B");
//お客さんを順番に並ばせる係員
CustomerManager customerManager = new CustomerManager(queue);
atmA.start();
atmB.start();
customerManager.start();
long limit = 20000; //閉店までの時間(ミリ秒)
long start = System.currentTimeMillis(); //開店時間(ミリ秒)
long now = System.currentTimeMillis(); //現在時間(ミリ秒)
while (now < start + limit) {
//閉店時間まで待つ
now = System.currentTimeMillis();
}
//閉店する
atmA.closeAtm();
atmB.closeAtm();
customerManager.closeBank();
queue.stop();
}
}
//順番待ちをする場所をあらわすクラス
class Queue {
LinkedList queue;
boolean acceptance = true;
public Queue() {
queue = new LinkedList();
}
//受付を終了するメソッド
synchronized public void stop() {
acceptance = false;
notifyAll();
}
//お客さんを順番待ちに追加するメソッド
synchronized public void put(Customer customer) {
queue.addFirst(customer);
printList();
System.out.println(customer.getNumber() + "番のお客さんが並びました。");
notifyAll();
}
//お客さんを順番待ちから削除してATMへ渡すメソッド
synchronized public Customer get() {
while (queue.size() == 0 && acceptance) {
try {
wait();
} catch (InterruptedException e) {
}
}
Customer customer = null;
if (queue.size() != 0) {
customer = (Customer)queue.removeLast();
}
printList();
notifyAll();
//順番待ちをしているお客さんがいればその人を、いなければnullを返す
return customer;
}
//順番待ちのお客さんを表示するメソッド
synchronized public void printList() {
System.out.print("順番待ち行列 [ ");
for (Iterator i = queue.iterator(); i.hasNext();) {
System.out.print(((Customer)i.next()).getNumber() + " ");
}
System.out.println("]");
}
}
//来店したお客さんを順番に並ばせる係員をあらわすクラス
class CustomerManager extends Thread {
private Queue queue;
private boolean open = true;
public CustomerManager(Queue queue) {
this.queue = queue;
}
public void run() {
int i = 1; //整理番号
while (open) {
//お客さんが来店する
Customer customer = new Customer();
//整理番号を渡す
customer.setNumber(i++);
//お客さんを順番待ちの最後に並ばせる
queue.put(customer);
try {
Thread.sleep((long) (Math.random() * 6000)); //平均3秒(6秒以下のランダムな時間)
} catch (InterruptedException e) {
}
}
}
public void closeBank() {
open = false;
}
}
//ATMをあらわすクラス
class Atm extends Thread {
private String atmName;
private Queue queue;
private boolean open = true;
public Atm(Queue queue, String atm) {
this.queue = queue;
this.atmName = atm;
}
public void run() {
while (open) {
//順番待ちしている先頭のお客さんを呼ぶ
Customer customer = queue.get();
//順番待ちのお客さんがいた場合
if (customer != null) {
System.out.println(customer.getNumber() + "番のお客さんがATM「" + atmName + "」を利用中です。");
try {
Thread.sleep((long) (Math.random() * 4000)); //平均2秒(4秒以下のランダムな時間)
} catch (InterruptedException e) {
}
System.out.println(customer.getNumber() + "番のお客さんが帰り、ATM「" + atmName + "」が空きました。");
}
}
System.out.println("ATM「" + atmName + "」は閉店しました。");
}
public void closeAtm() {
open = false;
}
}
//お客さんをあらわすクラス
class Customer {
private int number; //整理番号
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
}

