线程情况下两个堆栈实现一个队列
2013-05-29 00:29
351 查看
前言:这是一个很经典的问题,我之所以要写这个题,是因为我同学面试360时面试过一道题,当时面试官对他说,你们写代码的时候要考虑多线程访问时应该怎么办,所以我就尝试如果是线程访问的情况下两个堆栈实现一个队列应该怎么做?
一、问题描述和算法:
用堆栈实现队列的功能,可以用两个堆栈(stack1和stack2)实现队列的功能,理解一下三句话:
1当有新元素时直接保存到堆栈stack1中
2当要取出一个元素时从stack2中取出
3stack1中的元素导出再存放在stack2中,这样stack2中出去元素就是FIFO了
需要补充的是:当stack2为空时时,需要从stack1中取出全部元素放到stack2中,当stack1和stack2都为空时,队列为空。
二、算法java实现
package util; import java.util.*; public class MyQueue<T> { private Stack<T> stack1; private Stack<T> stack2; public MyQueue() { stack1=new Stack<T>(); stack2=new Stack<T>(); } public void appendTail(T item) { stack1.push(item); } public T deleteHead() throws Exception { if(stack2.empty()) { while(!stack1.empty()) { T item=stack1.pop(); stack2.push(item); } } if(stack2.empty()) { throw new Exception("队列空了,需要休息"); } T item=stack2.pop(); lock_stack2.unlock(); return item; } }
三、多线程访问的情况 为了简单分析我们假设只有两个线程,一个线程作为生产者,生产元素放入到队列中,另一个线程作为消费者,从队列中取出元素。那么当stack2的元素为空时,要从stack1转移元素,而且是一次性把所有元素都转移走,这个时候如果插入元素时,stack1就会进行push操作,那么就会出现问题,因此stack1本身可以认为是一个临界区(这块如果我理解有错误,请指出),因此可以通过加锁的形式把元素转移变化为一个原子操作。stack1去push元素时,首先要看是否可以在进行元素转移操作。 下面是代码
package util; import java.util.*; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class MyQueue<T> { private Lock lock_stack1; private Lock lock_stack2; private Stack<T> stack1; private Stack<T> stack2; public MyQueue() { lock_stack1=new ReentrantLock(); lock_stack2=new ReentrantLock(); stack1=new Stack<T>(); stack2=new Stack<T>(); } public void appendTail(T item) { lock_stack1.lock(); stack1.push(item); lock_stack1.unlock(); } public T deleteHead() throws Exception { lock_stack2.lock(); if(stack2.empty()) { lock_stack1.lock(); System.out.println("锁了"); System.out.print(stack1.size()); while(!stack1.empty()) { T item=stack1.pop(); stack2.push(item); } lock_stack1.unlock(); } if(stack2.empty()) { throw new Exception("队列空了,需要休息"); } T item=stack2.pop(); lock_stack2.unlock(); return item; } }
四、验证问题 我分别写了两个线程为生产者和消费者两个类,生产者生产的是数字,而且是从0,1,2,3,4,......这样的数字,消费者每次从队列中取出的数字也应该是0,1,2,3,4,....,如果消费者上次取出的数字是j,这次取出的数字是i,如果i<=j就代表出现问题了,因为队列输入的数据是严格递增的,因此输出的数据也是严格递增的。 下面是生产者和消费者的代码。消费者如果发现不满足这一条件时,就会报错,可以尝试注释掉队列中的锁条件,看看是否会报错。当我注释掉相关锁时,显示出报错信息。
package test; import util.MyQueue; public class Program { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub MyQueue<Integer> mq=new MyQueue<Integer>(); Producer myp=new Producer(mq); Consumer myc=new Consumer(mq); Thread tp=new Thread(myp); myc.start(); tp.start(); while(true) { } } }main代码
五、还存在的问题 目前只是解决了一个生产者和一个消费者的问题,没有解决多个消费者和多个生产者的问题,因为目前我还没有找到很好的方法验证多个消费者和多个消费者他们并发时应该产生的FIFO序列是什么?如果不是的话那就证明我出错了。如果大家有兴趣的话,希望大家指点一下。 菜包子 2013年5月29日0:18:36 于宿舍
相关文章推荐
- 两个堆栈实现一个队列 , 利用两个队列实现一个堆栈(Java)
- 两个堆栈实现一个队列
- 怎么用两个堆栈实现一个队列?
- 用两个堆栈实现一个列表的功能(主要是入队列和出队列)
- 剑指offer——用两个堆栈实现一个队列
- 两个堆栈实现一个队列和一叠两个队列实现【算法导论课后题】
- c++实现两个堆栈模拟一个队列
- 算法面试题:使用两个堆栈实现一个队列
- 数据结构面试题:两个队列实现一个堆栈
- 用两个堆栈实现一个队列
- 高频面试题之三种方法实现两个栈实现一个队列
- 使用两个队列实现一个栈
- 用两个栈(Stack)实现一个队列(Queue)
- 用两个队列实现一个栈
- 两个栈实现一个队列(java)
- 用两个栈实现一个队列的功能,用Java实现
- 数据结构--两个栈实现一个队列
- 使用两个栈实现一个队列
- 4-7 在一个数组中实现两个堆栈 (20分)
- 两个队列实现一个栈