public class MyQueue {
//初始化一个容器
private LinkedList<Object> list = new LinkedList<Object>();
private AtomicInteger count = new AtomicInteger(0);
private final int minSize = 0;
private final int maxSize;
public MyQueue(int maxSize) {
this.maxSize = maxSize;
}
public int getSize() {
return count.get();
}
private final Object lock = new Object();
public void put(Object obj) {
synchronized(lock) {
while (count.get() == this.maxSize) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
list.add(obj);
count.incrementAndGet();
lock.notify(); //通知由于容器空而阻塞的线程
System.out.println("新加入的元素为:" + obj);
}
}
public Object take() {
Object ret = null;
synchronized(lock) {
while (count.get() == this.minSize) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
ret = list.removeFirst();
count.decrementAndGet();
lock.notify(); //通知由于容器满而阻塞的线程
System.out.println("移除的元素为:" + ret);
}
return ret;
}
public static void main(String[] args) {
final MyQueue mq = new MyQueue(5); //必须加final修饰,否则线程中无法使用
mq.put("a1");
mq.put("b2");
mq.put("c3");
mq.put("d4");
mq.put("e5");
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
mq.put(System.currentTimeMillis());
mq.put(System.currentTimeMillis());
}
}, "t1");
t1.start();
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
mq.take();
mq.take();
}
}, "t2");
t2.start();
}
}
- 模拟的是只有一个生产者和一个消费者的情形。如果要模拟多生产者和多消费者的情形,可以使用循环来加多个t1线程作为生产者,多个t2线程作为消费者。
- 如果想让该程序无限运行下去,可以将put操作和take操作分别放在一个while(true)的死循环里面。
- TimeUnit.SECONDS.sleep()方法比Thread.sleep()更直观。如TimeUnit.SECONDS.sleep(2),很容易知道是2秒,而Thread.sleep(2 * 1000)。从效率上来说,二者几乎没有差别。