什么是队列?
队列是一种数据存储的结构,实例化的队列就是一种数据容器,用特定的规则来存储数据的容器。队列遵循先进先出原则,一般可以使用数组和链表来实现队列,且队列的进队只从屁股rear开始,出列从front开始。
队列实现需要注意哪些?
队列必须的属性需要有实现数据存储的容器、队列的容量、rear以及front。方法需要有进队方法,以及出对方法。此外进队需要判断队列是否已满,出对判断队列是否已空等,这便是实现一个队列的基本关注点。此外,往细了考虑,什么情况是队列满了呢?初始时队列为空,rear与front均是-1,rear的取值范围是-1 到 maxSize-1.而front的取值范围也是-1到maxSize。队列满时则rear必须是maxSize-1且front!=rear,而队列为空时,则一定是rear=front时。
记录代码实现
class PQueue{ private static PQueue pQueue; private int[] array;//声明一个数组,用作这个队列的容器 private int maxSize;//队列的大小 private int rear;//队列的后端,初始-1 private int front;//队列的前端-1(front永远指向队列的前一个数),初始-1 //初始化队列--禁止外部调用 private PQueue(int maxSize){ this.maxSize = maxSize; array = new int[this.maxSize]; rear = -1; front = -1; } //线程安全的单利模式 public static PQueue getInstance(int maxSize){ if(null == pQueue){ synchronized (PQueue.class){ pQueue = new PQueue(maxSize); } } return pQueue; } //判断队列是否已满 public boolean isFull(){ return rear == maxSize-1?false:true && rear!=front; } //判断队列是否为空 public synchronized boolean isEmpty(){ return rear == front?false:true; } //队列中增加元素 public void addPQueue(int num){ //先判断队列已满 if(isFull()){ rear++; array[rear]=num; return; } System.out.println("队列已满,添加元素失败"); throw new RuntimeException("队列已满,添加元素失败"); } //队列中删除元素--可能会有多个线程同时操作,需线程安全 public synchronized int getPQueue(){ //判断队列是否为空 if(isEmpty()){ front++; return array[front]; } System.out.println("队列为空,删除元素失败"); throw new RuntimeException("队列为空,删除元素失败"); } //展示队列中所有元素 public int[] showPQueue(){ //数组长度为rear减去front,因front指向数组的前一个值 int[] realArray = new int[rear-front]; int index=0;//初始化realArray的下标。 for(int i=0;i<array.length;i++){ //将有效的数据加入到真实数组中 if(i>front && i<=rear){ realArray[index]=array[i]; index++; } } return realArray; } }
队列的应用场景在哪?
1.最常见的就是排队系统,你必须保证先取号的人,最先被服务,这种常见的就是各个银行等。这里模拟下银行排队系统(线程通信并未实现,有线程安全风险)
代码如下
//模拟银行业务的线程A class OperatorA implements Runnable{ PQueue pQueue = PQueue.getInstance(20); @Override public void run() { while (pQueue.isEmpty()){ System.out.println("请"+pQueue.getPQueue()+"号客户前往A窗口办理业务!"); System.out.println("业务处理中。。。"); try { Thread.currentThread().sleep(3000);//假设A窗口处理业务需要3秒钟 } catch (InterruptedException e) { e.printStackTrace(); } } } } //模拟银行业务的线程B class OperatorB implements Runnable{ PQueue pQueue = PQueue.getInstance(20); @Override public void run() { while(pQueue.isEmpty()){ System.out.println("请"+pQueue.getPQueue()+"号客户前往B窗口办理业务!"); System.out.println("业务处理中。。。"); try { Thread.currentThread().sleep(4000);//假设B窗口处理业务需要4秒钟 } catch (InterruptedException e) { e.printStackTrace(); } } } } //模拟银行业务的线程C class OperatorC implements Runnable{ PQueue pQueue = PQueue.getInstance(20); @Override public void run() { while(pQueue.isEmpty()){ System.out.println("请"+pQueue.getPQueue()+"号客户前往C窗口办理业务!"); System.out.println("业务处理中。。。"); try { Thread.currentThread().sleep(5000);//假设C窗口处理业务需要5秒钟 } catch (InterruptedException e) { e.printStackTrace(); } } } }
执行代码
PQueue pQueue = PQueue.getInstance(13); //假设有13个人取了票在排队 pQueue.addPQueue(1); pQueue.addPQueue(2); pQueue.addPQueue(3); pQueue.addPQueue(4); pQueue.addPQueue(5); pQueue.addPQueue(6); pQueue.addPQueue(7); pQueue.addPQueue(8); pQueue.addPQueue(9); pQueue.addPQueue(10); pQueue.addPQueue(11); pQueue.addPQueue(12); pQueue.addPQueue(13); //银行窗口开始工作 Thread threadA = new Thread(new OperatorA()); Thread threadB = new Thread(new OperatorB()); Thread threadC = new Thread(new OperatorC()); threadA.start(); threadB.start(); threadC.start();
执行结果
请1号客户前往A窗口办理业务! 业务处理中。。。 请2号客户前往C窗口办理业务! 业务处理中。。。 请3号客户前往B窗口办理业务! 业务处理中。。。 请4号客户前往A窗口办理业务! 业务处理中。。。 请5号客户前往B窗口办理业务! 业务处理中。。。 请6号客户前往C窗口办理业务! 业务处理中。。。 请7号客户前往A窗口办理业务! 业务处理中。。。 请8号客户前往B窗口办理业务! 业务处理中。。。 请9号客户前往A窗口办理业务! 业务处理中。。。 请10号客户前往C窗口办理业务! 业务处理中。。。 请11号客户前往A窗口办理业务! 业务处理中。。。 请12号客户前往B窗口办理业务! 业务处理中。。。 请13号客户前往C窗口办理业务! 业务处理中。。。