模拟要点:
1.什么事阻塞队列?如何进行模拟一个阻塞队列?
2.拥有固定长度承载元素的容器。
3.计数统计容器的容量大小。
4.当队列里面没有元素的时候执行线程要等待。
5.单队列元素已满的时候执行线程也需要等待。
//模拟阻塞Queue(队列)
public class MyQueue {
//1,定义队列的承载容器
private final LinkedList<Object> list = new LinkedList<>();
/*2,计数器AtomicInteger是Integer的升级版,可以理解为一个int类型的count(计数器),
* 支持并发的计数器;它能实现单个服务之间的原子性,它在并发下单个服务可以保障
数据的一致性。*/
private final AtomicInteger count = new AtomicInteger(0);
private final int maxSize; //最大容量限制,此处为进行赋值会报异常,在下面使用构造器进行赋值
private final int minSize = 0;
//3,定义一个Object锁lock
private final Object lock = new Object();
public MyQueue(int maxSize) {
this.maxSize = maxSize;
}
//4,需要定义两个方法,一个put,一个take;
//定义put方法,实现放入元素功能
public void put(Object obj) {
//放入元素要先判断容器是否已经存满,如何存满就要等待,有位置就加入元素
//需要应用synchronized进行加锁
synchronized(lock) {
//使用while循环不断进行循例判断count计数器是否等于容器最大容量限制maxSize
while(count.get() == this.maxSize) {
//相对就要等待,使用Object的wait方法
try {
lock.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//未到最大容量限制,就使用容器的add方法将新元素加入容器
list.add(obj);
//添加了新元素,计数器加加1,AtomicInteger计数器提供两个方法分别对应i++和++i
count.getAndIncrement();//此为i++,即为获取后递增
//count.incrementAndGet();//此为++i
System.out.println("元素:"+obj+"已经添加到容器中");
//进行唤醒可能正在等待的take方法处于操作中的等待线程,*put与take分别为两个不同的线程*:
//在添加新元素进来的时候就要考虑到是否有临界等待的线程有待唤醒
lock.notify();//唤醒take方法线程
}
}
//定义take方法,实现获取元素,如果容器为空即为minSize,则等待新元素加入后在执行
public Object take() {
Object temp = null;
synchronized(lock) {
while(count.get() == minSize) {
try {
lock.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//被唤醒后要拿到元素,保持先进先出的原则,那么就是获取头元素
temp = list.removeFirst();
//计数器要递减
count.getAndDecrement(); //i--
System.out.println("元素:"+temp+"已经从容器中取走");
//进行唤醒可能正在等待的put方法处于操作中的等待线程,
//此处考虑的临界状态为当maxSize已经为最大容量,put线程就会处于等待状态,
//在此take方法已经将头元素取走,意味着容器已经有可容纳空间,所有唤醒put方法的等待线程
lock.notify();//唤醒put方法线程
}
return temp;
}
//获取容器大小
public int size() {
return count.get();
}
public List<Object> getQueueList() {
return list;
}
}
//测试MyQueue
public class MyQueueTest {
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
MyQueue mq = new MyQueue(5);
mq.put("a");
mq.put("b");
mq.put("c");
mq.put("d");
mq.put("e");
System.out.println("当前元素个数:"+mq.size());
//模拟临界值状态,新创建一个线程
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
mq.put("f");
mq.put("g");
}
},"t1");
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
try {
Thread.sleep(1000);
Object o1 = mq.take();
Thread.sleep(1000);
Object o2 = mq.take();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
},"t2");
/*
Thread.sleep(1000);
System.out.println("当前元素个数:"+mq.size());
*/
t1.start();
Thread.sleep(1000);
t2.start();
Thread.sleep(5000);
System.out.println(mq.getQueueList().toString());
}
}
输出结果:
元素:a已经添加到容器中
元素:b已经添加到容器中
元素:c已经添加到容器中
元素:d已经添加到容器中
元素:e已经添加到容器中
当前元素个数:5
元素:a已经从容器中取走
元素:f已经添加到容器中
元素:b已经从容器中取走
元素:g已经添加到容器中
[c, d, e, f, g]