Java并发编程学习记录

银行出纳员仿真

2020-03-21  本文已影响0人  桐桑入梦
package concurrency;

import java.io.IOException;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Random;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

class Customer{
    private final int serviceTime;

    public Customer(int serviceTime){
        this.serviceTime = serviceTime;
    }

    public int getServiceTime(){
        return serviceTime;
    }

    @Override
    public String toString(){
        return "[" + serviceTime + "]";
    }
}

class CustomerLine extends ArrayBlockingQueue<Customer>{
    public CustomerLine(int maxLineSize){
        //初始化调用父类的构造函数
        super(maxLineSize);
    }

    public String toString(){
        if(this.size() == 0)
            return "[Empty]";
        StringBuilder result = new StringBuilder();
        for(Customer customer : this)
            result.append(customer);
        return result.toString();
    }
}

class CustomerGenerator implements Runnable{
    //阻塞队列,用于添加用户
    private CustomerLine customers;
    private Random rand = new Random(47);

    public CustomerGenerator(CustomerLine customers){
        this.customers = customers;
    }

    @Override
    public void run(){
        try{
            while(!Thread.interrupted()){
                //在随机睡眠一段之间之后向阻塞队列中添加一个顾客元素
                TimeUnit.MILLISECONDS.sleep(rand.nextInt(300));
                customers.put(new Customer(rand.nextInt(1000)));
            }
        }catch(InterruptedException e){
            System.out.println("CustomerGenerator interuped");
        }
        System.out.println("CustomerGenerator terminating");
    }
}

class Teller implements Runnable, Comparable<Teller>{
    private static int counter = 0;
    private final int id = counter++;
    private CustomerLine customers;
    private int customerServied = 0;
    private boolean servingCustomerLine = true;

    public Teller(CustomerLine customers){
        this.customers = customers;
    }

    @Override
    public void run(){
        try{
            while(!Thread.interrupted()){
                //从阻塞队列取出一个顾客元素,为她服务一段时间
                Customer customer = customers.take();
                TimeUnit.MILLISECONDS.sleep(customer.getServiceTime());
                //更新出纳员已经服务的顾客人数,需要加锁访问
                synchronized(this){
                    customerServied++;
                    //判断是否需要继续工作,如果不需要,那么阻塞等待
                    while(!servingCustomerLine)
                        wait();
                }
            }
        }catch(InterruptedException e){
            System.out.println(this + "interrupted");
        }
        System.out.println(this + "terminating");
    }

    //如果顾客不是很多,调用此方法,让出纳员休息或者做其他的事情
    public synchronized void doSomethingElse(){
        customerServied = 0;
        servingCustomerLine = false;
    }

    //让出纳员处理顾客
    public synchronized void serveCustomerLine(){
        //如果这个出纳员正在休息,那么打印already...
        assert !servingCustomerLine : "already serving: " + this;
        servingCustomerLine = true;
        //唤醒休息的出纳员,不是唤醒所有的出纳员,只是当前的这个
        notifyAll();
    }

    @Override
    public String toString(){
        return "Teller " + id + " ";
    }

    public String shortString(){
        return "T" + id;
    }

    @Override
    public synchronized int compareTo(Teller that){
        //比较之后的顺序是 -1 , 0  , 1
        return customerServied < that.customerServied ? -1 : ( customerServied == that.customerServied ? 0 : 1);
    }
}

class TellerManager implements Runnable{
    private ExecutorService exec;
    //顾客对应的阻塞队列,方便招聘出纳员时候引用队列
    private CustomerLine customers;
    //按照工作量小的出纳员优先接待顾客,这里是正在做出纳工作的Tellers
    private PriorityQueue<Teller> workingTellers = new PriorityQueue<>();
    //做其他事情的出纳员
    private Queue<Teller> tellersDoingOtherThings = new LinkedList<>();
    private int adjustmentPeriod;
    private static Random rand = new Random(47);

    public TellerManager(ExecutorService exec, CustomerLine customers, int adjustmentPeriod){
        this.exec = exec;
        this.customers = customers;
        this.adjustmentPeriod = adjustmentPeriod;

        Teller teller = new Teller(customers);
        workingTellers.add(teller);
        exec.execute(teller);
    }

    public void adjustTellerNumber(){
        //如果顾客的数量很多,那么添加Teller数量
        if(customers.size() / workingTellers.size() > 2){
            //如果有空闲的Teller,那么添加到工作队列
            if(tellersDoingOtherThings.size() > 0){
                //从其他的事情(阻塞中)中出来,进入工作的优先队列中
                Teller teller = tellersDoingOtherThings.remove();
                //唤醒阻塞的该任务
                teller.serveCustomerLine();
                //优先队列的offer方法和add方法类似
                workingTellers.offer(teller);
                return ;
            }
            Teller teller = new Teller(customers);
            exec.execute(teller);
            workingTellers.add(teller);
            return ;
        }

        //如果工作人员不止一个,而且等待的顾客不是很多,那么这里只用一个Teller
        if(workingTellers.size() > 1 && customers.size() / workingTellers.size() < 2){
            //让Teller休息(阻塞)
            reassingOneTeller();
        }

        if(customers.size() == 0)
            while(workingTellers.size() > 1)
                reassingOneTeller();
    }

    private void reassingOneTeller(){
        Teller teller = workingTellers.poll();
        teller.doSomethingElse();
        tellersDoingOtherThings.offer(teller);
    }

    @Override
    public void run() {
        try{
            while(!Thread.interrupted()){
                //每隔一段时间,调整Teller的数量
                TimeUnit.MILLISECONDS.sleep(adjustmentPeriod);
                adjustTellerNumber();
                System.out.print(customers + " {");
                for(Teller teller : workingTellers)
                    System.out.print(teller.shortString() + " ");
                System.out.println("}");
            }
        }catch(InterruptedException e){
            System.out.println(this + "interrupted");
        }
        System.out.println(this + "terminating");
    }

    @Override
    public String toString(){
        return "TellerManager ";
    }
}

//银行出纳员仿真
public class BankTellerSimulation {
    static final int MAX_LINE_SIZE = 50;
    static final int ADJUSTMENT_PERIOD = 1000;

    public static void main(String[] args) throws InterruptedException, IOException {
        ExecutorService exec = Executors.newCachedThreadPool();
        CustomerLine customers = new CustomerLine(MAX_LINE_SIZE);
        //Customer生成器用于生成客户的阻塞队列,请求出纳员的服务
        exec.execute(new CustomerGenerator(customers));
        //传入exec是为了方便提交新的Teller任务
        exec.execute(new TellerManager(exec, customers, ADJUSTMENT_PERIOD));

        //运行指定的之间之后退出
        if(args.length > 0)
            TimeUnit.SECONDS.sleep(Integer.parseInt(args[0]));
        else{
            System.out.println("Press 'Enter' to quit");
            System.in.read();
        }
        exec.shutdownNow();
    }
}
上一篇下一篇

猜你喜欢

热点阅读