阻塞队列使用自己写的,前篇文章自己实现阻塞队列里有介绍,现在代码贴过来
阻塞队列实现方式一 使用synchronized
import java.util.ArrayList;
import java.util.List;
public class SelfQueue<T> {
//默认阻塞队列容量
private static int DEFAULT_CAPACITY = 3;
private List<T> list;
/**
* 无惨构造
* 使用默认容量初始化队列
*/
public SelfQueue() {
list = new ArrayList<>(DEFAULT_CAPACITY);
}
/**
* 有参构造
* 自定义队列容量
*/
public SelfQueue(int capacity) throws Exception {
DEFAULT_CAPACITY = capacity;
list = new ArrayList<>(capacity);
}
/**
* 阻塞放
*/
public void put(T t) {
synchronized (SelfQueue.class) {
while (list.size() == DEFAULT_CAPACITY) {
try {
//等待
SelfQueue.class.wait();
} catch (InterruptedException e) {
System.out.println("put error!");
}
}
//队列中元素个数少于队列容量时唤醒
if (list.size() < DEFAULT_CAPACITY) {
//唤醒
SelfQueue.class.notify();
}
list.add(t);
}
}
/**
* 阻塞取
*/
public T take() {
synchronized (SelfQueue.class) {
while (list.size() == 0) {
try {
//等待
SelfQueue.class.wait();
} catch (InterruptedException e) {
System.out.println("take error!");
}
}
//队列中元素个数大于0时唤醒
if (list.size() > 0) {
//唤醒
SelfQueue.class.notify();
}
return list.remove(0);
}
}
}
阻塞队列实现方式二 使用lock+condition
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class SelfQueue<T> {
private static int CAPACITY = 3;
private List<T> list;
private Lock lock;
private Condition condition;
SelfQueue() {
this(CAPACITY);
}
SelfQueue(int capacity) {
this.CAPACITY = capacity;
list = new ArrayList<>(CAPACITY);
lock = new ReentrantLock();
condition = lock.newCondition();
}
public void put(T t) {
lock.lock();
while (list.size() == CAPACITY) {
try {
condition.await();
} catch (InterruptedException e) {
System.out.println("put error!");
}
}
if (list.size() < CAPACITY) {
condition.signal();
}
list.add(t);
lock.unlock();
}
public T take() {
lock.lock();
while (list.size() == 0) {
try {
condition.await();
} catch (InterruptedException e) {
System.out.println("take error!");
}
}
if (list.size() > 0) {
condition.signal();
}
T t = list.remove(0);
lock.unlock();
return t;
}
}
生产者类
/**
* 生产者类
*/
class Producer implements Runnable {
private SelfQueue<String> queue;
public Producer(SelfQueue queue) {
this.queue = queue;
}
@Override
public void run() {
System.out.println("生产者" + Thread.currentThread().getName() + " ...");
queue.put(Thread.currentThread().getName());
}
}
消费者类
/**
* 消费者类
*/
class Consumer implements Runnable {
private SelfQueue<String> queue;
public Consumer(SelfQueue queue) {
this.queue = queue;
}
@Override
public void run() {
System.out.println("消费者" + Thread.currentThread().getName() + ": " + queue.take());
}
}
测试
public static void main(String[] args) throws Exception {
SelfQueue<String> queue = new SelfQueue<>(8);
Consumer consumer = new Consumer(queue);
Producer producer = new Producer(queue);
for (int i = 0; i < 8; i++) {
new Thread(producer).start();
new Thread(consumer).start();
}
}
结果
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
前段时间去面试,面试官说ArrayList.remove(0),下一次在放入元素的时候会放到这个0的位置,然后再取的情况就会取0位置而非1位置的,就没法做到了FIFO。开始没考虑这些,回头看了下源码,底层做remove的时候,会调用一个native方法,做数组的拷贝,但是再放入的时候并不是放再0位置,而是放入最后一个元素的后面,所以我用ArrayList这种写法并没有错,也同样可以实现FIFO。但自己仔细考虑了下,生产者和消费者模式大部分元素都是进进出出,大部分修改操作,几乎很少查询,结合链表和数组的特性,这种情况用LinkedList应该更好点,并且LinkedList底层不需要连续空间,无论效率上还是情景贴合度应该都更好点。