手写模拟一个自己的 阻塞队列 MyQueue
package com.example.demo.edu51;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
//定义一个 阻塞队列
public class MyQueue {
// 1. 定义一个容器
private final ArrayList<String> list = new ArrayList<>();
private final LinkedList<String> ll = new LinkedList<>();
// 2. 计数器
// AtomicInteger 实现单个服务之间的原子性,支持并发,并发下保证单个服务的数据一致性,不会造成数据错误
private final AtomicInteger count = new AtomicInteger(0);
// 最大容量
private final int maxSize;
private final int minSize = 0;
private Object lock = new Object();
public MyQueue (int size) {
this.maxSize = size;
}
public void put(String s) {
synchronized(lock) {
// 如果容器容量已满,则线程等待
while(count.get() == maxSize) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 跳出while循环,这说明容器中有位置可以加入新元素
ll.add(s);
count.getAndIncrement();// 等同于 i++
System.out.println(" ++ "+s + " "+count.get()+ " "+Thread.currentThread().getName());
// 容器有元素了, 唤醒 正在做 take 操作,等待(取走元素)中的线程
lock.notify();
}
}
public String take() {
String temp = null;
synchronized(lock) {
// 如果容器中没有元素,wait
while(count.get() == minSize) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// count.get() != 0,容器中有元素了, 取走首位元素
temp = ll.removeFirst();
count.getAndDecrement(); // 等同于 i--
System.out.println(" -- "+temp+ " "+count.get()+ " "+Thread.currentThread().getName());
// 取走一个, 容器中有位置了, 唤醒真在做put操作的等待中的线程
lock.notify();
}
return temp;
}
public int size() {
return count.get();
}
public List<String> getQueue(){
return ll;
}
}
测试类:
package com.example.demo.edu51;
public class MyQueueTest {
public static void main(String[] args) {
MyQueue mq = new MyQueue(5);
mq.put("1");
mq.put("2");
mq.put("3");
mq.put("4");
mq.put("5");
System.err.println("size1 : "+mq.size());
Thread put1 = new Thread(new Runnable() {
@Override
public void run() {
mq.put("put1_1");
mq.put("put1_2");
mq.put("put1_3");
mq.put("put1_4");
}
},"put1");
System.err.println("size2 : "+mq.size());
Thread put2 = new Thread(new Runnable() {
@Override
public void run() {
mq.put("p2_1");
mq.put("p2_2");
mq.put("p2_3");
mq.put("p2_4");
}
},"put2");
Thread put3 = new Thread(new Runnable() {
@Override
public void run() {
mq.put("p3_1");
mq.put("p3_2");
mq.put("p3_3");
}
},"put3");
Thread put4 = new Thread(new Runnable() {
@Override
public void run() {
mq.put("p4_1");
mq.put("p4_2");
}
},"put4");
put1.start();
put2.start();
put3.start();
put4.start();
// take **************************************************
Thread take1 = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
mq.take();
Thread.sleep(1000);
mq.take();
Thread.sleep(1000);
mq.take();
Thread.sleep(1000);
mq.take();
Thread.sleep(1000);
mq.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"take1");
Thread take2 = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
mq.take();
Thread.sleep(1000);
mq.take();
Thread.sleep(1000);
mq.take();
Thread.sleep(1000);
mq.take();
Thread.sleep(1000);
mq.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"take2");
take1.start();
take2.start();
try {
Thread.sleep(7000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.err.println(" 元素 "+ mq.getQueue().toString());
}
}
控制台打印:
size1 : 5
++ 1 1 main
++ 2 2 main
++ 3 3 main
++ 4 4 main
++ 5 5 main
size2 : 5
-- 1 4 take2
++ put1_1 5 put1
-- 2 4 take1
++ p3_1 5 put3
-- 3 4 take1
++ p2_1 5 put2
-- 4 4 take2
++ p3_2 5 put3
-- 5 4 take2
++ p2_2 5 put2
-- put1_1 4 take1
++ p3_3 5 put3
-- p3_1 4 take1
++ put1_2 5 put1
-- p2_1 4 take2
++ p4_1 5 put4
-- p3_2 4 take2
++ p2_3 5 put2
-- p2_2 4 take1
++ put1_3 5 put1
元素 [p3_3, put1_2, p4_1, p2_3, put1_3]