java 排队_JAVA实现排队论
个人博客站已经上线了,网址 www.llwjy.com ~欢迎各位吐槽~
-------------------------------------------------------------------------------------------------
前段时间去银行办业务,排队的人那是真多。自己正式办理业务也就不到5分钟,可是却足足等了两个小时(相信非常多人都遇到过这样的情况),对这样的服务水平真的是无语了,可是问题又来了。银行应该开几个窗体,既能保证总体的服务质量,又能保证资源资源的利用率呢?以下我们就通过排队论来模拟这个问题。
排队论简单介绍
排队论是研究系统随机聚散现象和随机系统工作project的数学理论和方法,又称随机服务系统理论。为运筹学的一个分支。
我们以下对排队论做下简化处理,先看下图:
我们在图的左側安排若干个蓝色服务台,右側为可能会过来的红色顾客,中间为黄色的等候区,假设有服务台处于空暇状态。顾客能够直接去接受服务,否则就要在黄色区域等候,顾客服务的顺序採用先到现服务的原则。如今假设我们知道顾客过来的概率分布,那么我们在左側安排几个服务台既能达到更好的服务水平,又能保证服务台的使用率?以下我们就构建模型来模拟这个问题。
排队论分步实现
1)对于排队论,我们首先要确定顾客属性,知道顾客什么时候到达,须要的服务耗时等,我们首先创建一个顾客类。在这里我们指定了顾客服务的最大、最小时间,这里我们为了简化就直接觉得服务时间全然随机:
public class CustomerBean {
//最小服务时间
private static int minServeTime = 3 * 1000;
//最大服务时间
private static int maxServeTime = 15 * 1000;
//顾客达到时间
private long arriveTime;
//顾客须要服务耗时
private int serveTime;
public CustomerBean() {
//设置到达时间
arriveTime = System.currentTimeMillis();
//随机设置顾客的服务时间
serveTime = (int) (Math.random() * (maxServeTime - minServeTime) + minServeTime);
}
}
2)上面我们定义了顾客。紧接着就须要定义一个排队队列,我们先看下队列的属性,这里我们定义一个数组。用它来保存排队的顾客,定义下一个顾客到来的最小、最大时间间隔以及顾客来不来的概率(这里简单说明下,假设下一个顾客的间隔时间是3。可是通过概率计算并为满足,则这个顾客不进入队列,这样设置的原因是尽可能的使顾客达到有非常大的随机性)和队列中最大的排队人数。
public class CustomerQuene {
//等待顾客队列
private LinkedList customers = new LinkedList();
//下一个顾客过来最短时间
private int minTime = 0;
//下一个顾客过来最大时间
private int maxTime = 1 * 1000;
//来顾客的概率
private double rate = 0.9;
//标识是否继续产生顾客
private boolean flag = true;
//最大排队人数
private int maxWaitNum = 0;
}
3)顾客和排队的队列都有了,我们就设置一个产生顾客的线程,让它不断的产生顾客。这里就有我们上面说的时间和概率分布。
/**
*@Description: 生成顾客线程
*@Author:lulei
*@Version:1.1.0
*/
private class CustomerThread extends Thread {
private CustomerThread(String name) {
super(name);
}
@Override
public void run() {
while (flag) {
//队尾加入一个新顾客
if (Math.random() < rate) {
customers.addLast(new CustomerBean());
if (maxWaitNum < customers.size()) {
maxWaitNum = customers.size();
}
}
int sleepTime = (int) (Math.random() * (maxTime - minTime) + minTime);
try {
TimeUnit.MILLISECONDS.sleep(sleepTime);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
4)假设队列中有顾客排队切有空暇的服务台,就须要获取队头的顾客去接受服务
public synchronized CustomerBean getCustomerBean() {
if (customers == null || customers.size() < 1) {
return null;
}
return customers.removeFirst();
}
5)顾客相关的属性和方法都已经准备好。以下就设置下服务台相关的属性,这里我们直接把服务台设置成线程,定义一些服务指标。如服务的顾客数目、总等待时间、总服务时间、最大等待时间等。
public class ServantThread extends Thread{
//服务顾客数目
private static int customerNum = 0;
//总等待时间
private static int sumWaitTime = 0;
//总服务时间
private static int sumServeTime = 0;
//最大等待时间
private static int maxWaitTime = 0;
private boolean flag = false;
private String name;
}
6)服务台最基本的工作就是服务顾客,这里我们把服务顾客相关的操作写到线程的run方法中。
public void run() {
flag = true;
while (flag) {
CustomerBean customer = CustomerQuene.getCustomerQuene().getCustomerBean();
//假设顾客线程已经关闭且队列中没有顾客。服务台线程关闭释放
if (customer == null) {
if (!CustomerQuene.getCustomerQuene().isFlag()) {
flag = false;
print();
}
continue;
}
long now = System.currentTimeMillis();
int waitTime = (int) (now - customer.getArriveTime());
//保存最大的等待时间
if (waitTime > maxWaitTime) {
maxWaitTime = waitTime;
}
//睡眠时间为顾客的服务时间。代表这段时间在服务顾客
try {
TimeUnit.MILLISECONDS.sleep(customer.getServeTime());
} catch (Exception e) {
e.printStackTrace();
}
System.err.println(name + " 服务顾客耗时:" + customer.getServeTime() + "ms\t顾客等待:" + waitTime + "ms");
customerNum++;
sumWaitTime += waitTime;
sumServeTime += customer.getServeTime();
}
}
7)最后我们编写一个測试模型,来验证服务水平
/**
*@Description:
*/
package com.lulei.opsearch.quene;
import java.util.concurrent.TimeUnit;
public class Test {
public static void main(String[] args) {
//开门
System.out.println("开门接客啦。");
boolean flag = true;
CustomerQuene.getCustomerQuene();
long a = System.currentTimeMillis();
int servantNum = 10;
for (int i = 0; i < servantNum; i++) {
ServantThread thread = new ServantThread("服务台" + i);
thread.start();
}
while (flag) {
long b = System.currentTimeMillis();
if (b - a > 1 * 60 * 1000 && flag) {
//关门
flag = false;
CustomerQuene.getCustomerQuene().close();
System.out.println("关门不接客啦!");
}
System.out.println("系统执行时间:" + (b -a) + "ms");
System.out.println("系统空暇时间:" + ((b -a) * servantNum - ServantThread.getSumServeTime()));
ServantThread.print();
try {
TimeUnit.SECONDS.sleep(2);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}执行结果
1)执行開始
2)顾客产生线程关闭
3)最后服务水平
通过改动服务台的个数就能够评估在当前的顾客情况下应该设置几个服务台。
完整代码
1)顾客类
/**
*@Description:
*/
package com.lulei.opsearch.quene;
public class CustomerBean {
//最小服务时间
private static int minServeTime = 3 * 1000;
//最大服务时间
private static int maxServeTime = 15 * 1000;
//顾客达到时间
private long arriveTime;
//顾客须要服务耗时
private int serveTime;
public CustomerBean() {
//设置到达时间
arriveTime = System.currentTimeMillis();
//随机设置顾客的服务时间
serveTime = (int) (Math.random() * (maxServeTime - minServeTime) + minServeTime);
}
public static int getMinServeTime() {
return minServeTime;
}
public static void setMinServeTime(int minServeTime) {
CustomerBean.minServeTime = minServeTime;
}
public static int getMaxServeTime() {
return maxServeTime;
}
public static void setMaxServeTime(int maxServeTime) {
CustomerBean.maxServeTime = maxServeTime;
}
public long getArriveTime() {
return arriveTime;
}
public void setArriveTime(long arriveTime) {
this.arriveTime = arriveTime;
}
public int getServeTime() {
return serveTime;
}
public void setServeTime(int serveTime) {
this.serveTime = serveTime;
}
}
2)顾客队列
/**
*@Description:
*/
package com.lulei.opsearch.quene;
import java.util.LinkedList;
import java.util.concurrent.TimeUnit;
public class CustomerQuene {
//等待顾客队列
private LinkedList customers = new LinkedList();
//下一个顾客过来最短时间
private int minTime = 0;
//下一个顾客过来最大时间
private int maxTime = 1 * 1000;
//来顾客的概率
private double rate = 0.9;
//标识是否继续产生顾客
private boolean flag = true;
//最大排队人数
private int maxWaitNum = 0;
public int getMaxWaitNum() {
return maxWaitNum;
}
public boolean isFlag() {
return flag;
}
/**
* @return
* @Author:lulei
* @Description: 获取排在队头的顾客
*/
public synchronized CustomerBean getCustomerBean() {
if (customers == null || customers.size() < 1) {
return null;
}
return customers.removeFirst();
}
public void close() {
if (flag) {
flag = false;
}
}
/**
* @return
* @Author:lulei
* @Description: 获取等待顾客数量
*/
public int getWaitCustomerNum() {
return customers.size();
}
/**
*@Description: 生成顾客线程
*@Author:lulei
*@Version:1.1.0
*/
private class CustomerThread extends Thread {
private CustomerThread(String name) {
super(name);
}
@Override
public void run() {
while (flag) {
//队尾加入一个新顾客
if (Math.random() < rate) {
customers.addLast(new CustomerBean());
if (maxWaitNum < customers.size()) {
maxWaitNum = customers.size();
}
}
int sleepTime = (int) (Math.random() * (maxTime - minTime) + minTime);
try {
TimeUnit.MILLISECONDS.sleep(sleepTime);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
//单例模式開始
private static class CustomerQueneDao {
private static CustomerQuene customerQuene = new CustomerQuene();
}
private CustomerQuene() {
CustomerThread customerThread = new CustomerThread("顾客产生线程");
customerThread.start();
}
public static CustomerQuene getCustomerQuene() {
return CustomerQueneDao.customerQuene;
}
//单例模式结束
public int getMinTime() {
return minTime;
}
public void setMinTime(int minTime) {
this.minTime = minTime;
}
public int getMaxTime() {
return maxTime;
}
public void setMaxTime(int maxTime) {
this.maxTime = maxTime;
}
public double getRate() {
return rate;
}
public void setRate(double rate) {
this.rate = rate;
}
}
3)服务台线程
/**
*@Description:
*/
package com.lulei.opsearch.quene;
import java.util.concurrent.TimeUnit;
import com.lulei.util.ParseUtil;
public class ServantThread extends Thread{
//服务顾客数目
private static int customerNum = 0;
//总等待时间
private static int sumWaitTime = 0;
//总服务时间
private static int sumServeTime = 0;
//最大等待时间
private static int maxWaitTime = 0;
private boolean flag = false;
private String name;
public ServantThread(String name) {
super(name);
this.name = name;
}
public static int getMaxWaitTime() {
return maxWaitTime;
}
public static int getSumServeTime() {
return sumServeTime;
}
@Override
public void run() {
flag = true;
while (flag) {
CustomerBean customer = CustomerQuene.getCustomerQuene().getCustomerBean();
//假设顾客线程已经关闭且队列中没有顾客。服务台线程关闭释放
if (customer == null) {
if (!CustomerQuene.getCustomerQuene().isFlag()) {
flag = false;
print();
}
continue;
}
long now = System.currentTimeMillis();
int waitTime = (int) (now - customer.getArriveTime());
//保存最大的等待时间
if (waitTime > maxWaitTime) {
maxWaitTime = waitTime;
}
//睡眠时间为顾客的服务时间,代表这段时间在服务顾客
try {
TimeUnit.MILLISECONDS.sleep(customer.getServeTime());
} catch (Exception e) {
e.printStackTrace();
}
System.err.println(name + " 服务顾客耗时:" + customer.getServeTime() + "ms\t顾客等待:" + waitTime + "ms");
customerNum++;
sumWaitTime += waitTime;
sumServeTime += customer.getServeTime();
}
}
public static void print() {
if (customerNum > 0) {
System.out.println("--------------------------------------");
System.out.println("服务顾客数目:" + customerNum);
System.out.println("最大等待时间:" + maxWaitTime);
System.out.println("等待顾客数目:" + CustomerQuene.getCustomerQuene().getWaitCustomerNum());
System.out.println("最大等待顾客数目:" + CustomerQuene.getCustomerQuene().getMaxWaitNum());
//输出顾客平均等待时间。保留两位小数
System.out.println("顾客平均等待时间:" + ParseUtil.parseDoubleToDouble((sumWaitTime * 1.0 / customerNum), 2) + "ms");
System.out.println("顾客平均服务时间:" + ParseUtil.parseDoubleToDouble((sumServeTime * 1.0 / customerNum), 2) + "ms");
System.out.println("系统总服务时间:" + sumServeTime + "ms");
}
}
}
4)測试模型
/**
*@Description:
*/
package com.lulei.opsearch.quene;
import java.util.concurrent.TimeUnit;
public class Test {
public static void main(String[] args) {
//开门
System.out.println("开门接客啦!
");
boolean flag = true;
CustomerQuene.getCustomerQuene();
long a = System.currentTimeMillis();
int servantNum = 10;
for (int i = 0; i < servantNum; i++) {
ServantThread thread = new ServantThread("服务台" + i);
thread.start();
}
while (flag) {
long b = System.currentTimeMillis();
if (b - a > 1 * 60 * 1000 && flag) {
//关门
flag = false;
CustomerQuene.getCustomerQuene().close();
System.out.println("关门不接客啦!");
}
System.out.println("系统执行时间:" + (b -a) + "ms");
System.out.println("系统空暇时间:" + ((b -a) * servantNum - ServantThread.getSumServeTime()));
ServantThread.print();
try {
TimeUnit.SECONDS.sleep(2);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
-------------------------------------------------------------------------------------------------
小福利
-------------------------------------------------------------------------------------------------
个人在极客学院上《Lucene案例开发》课程已经上线了。欢迎大家吐槽~
第七课:小说站点分布式爬虫的实现
java 排队_JAVA实现排队论相关推荐
- 【源码+教程】Java课设项目_12款最热最新Java游戏项目_Java游戏开发_Java小游戏_飞翔的小鸟_王者荣耀_超级玛丽_推箱子_黄金矿工_贪吃蛇
马上就要期末了,同学们课设做的如何了呢?本篇为大家带来了12款热门Java小游戏项目的源码和教程,助力大家顺利迎接暑假![源码+教程]Java课设项目_12款最热最新Java游戏项目_Java游戏开发 ...
- 黑马程序员全套Java教程_Java基础教程_异常(含扩展)(二十三)
黑马程序员全套Java教程_Java基础教程_异常(含扩展)(二十三) 1.1 异常概述与异常体系结构 1.2 JVM遇到异常时的默认处理方案 1.3 异常处理 1.4 异常处理之try--catch ...
- java排队论代码_Java实现排队论的原理
摘要:这篇Java开发技术栏目下的"Java实现排队论的原理",介绍的技术点是"Java.排队论.原理.实现",希望对大家开发技术学习和问题解决有帮助. 引入: ...
- 排队模拟JAVA程序_java 模拟窗口排队
public class MyQueue { private LinkedList q = new LinkedList(); /** * 排队 * @param e */ public synchr ...
- java排队叫号_java多线程(4)模拟排队叫号程序,不能出现交替执行的结果
package com.javaconcurrencyprogramming.chapter1; /** * @description: 模拟有错误的排队叫号程序 * @author: * @crea ...
- java 排队任务_android实现排队任务
相信大家做程序遇到比较多的就是队列,排队问题.对于app上这种问题比较多,比如排队下载,排队发送,并发排队网络请求等等. 要如何自己做好一个这样的功能呢. 下面我给大家将一下我对这一块的理解. 首先在 ...
- JAVA 海啸_java线程总结
首先要理解线程首先需要了解一些基本的东西,我们现在所使用的大多数操作系统都属于多任务,分时操作系统.正是由于这种操作系统的出现才有了多线程这个概念.我们使用的windows,linux就属于此列.什么 ...
- java命令_JAVA与模式之命令模式
在阎宏博士的<JAVA与模式>一书中开头是这样描述命令(Command)模式的: 命令模式属于对象的行为模式.命令模式又称为行动(Action)模式或交易(Transaction)模式. ...
- java 数据结构_Java版-数据结构-队列(数组队列)
前言 看过笔者前两篇介绍的 Java版数据结构 数组和 栈的盆友,都给予了笔者一致的好评,在这里笔者感谢大家的认可!!! 由于本章介绍的数据结构是 队列,在队列的实现上会基于前面写的 动态数组来实现, ...
- java排队系统模型,MMC排队系统模型
MMC排队系统模型及应用 M/M/C排队模型及其应用 摘要:将随机服务系统中M/M/C排队模型应用到理发服务行业中.通过对某理发店进行调查,以10min为一个调查单位调查顾客到达数,统计了72个调查单 ...
最新文章
- 《python核心编程第二版》第5章习题
- 开发IOT WiFi设备时,需要测试的几种情况
- wpf treeView,避免横向滚动条自动偏移。 ContentHorizontalOffset
- php 状态模式,PHP设计模式(十九)—状态模式 (State Pattern)
- 自学python(一)
- 理解zookeeper选举机制
- 云计算开发学习笔记:Python3迭代器与生成器
- 怎样写 OpenStack Neutron 的 Extension (三)
- 蓝桥杯 ALGO-85 算法训练 进制转换
- Java 2017.11.20 杨浩宁作业
- 网站后台开发 java_Java前后台开发
- 金针工具箱5.0安装版(多功能软件快捷工具)hh852作品
- 基于SSH框架的人力资源管理系统设计与实现
- Linux中jemalloc的安装与使用
- 稳压管和TVS管的工作原理
- 关于在线银行卡支付限额问题 解决方案
- ORB_SLAM2运行TUM数据和实时数据
- 华为nova7星耀版和华为nova7普通版 的区别 哪个好
- 【企业微信实现免密登录以及发送消息(企业内部应用)】
- 浏览器UA,浏览器标识检测