解答例 - 実習課題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; } }