# JUC.Condition实现阻塞队列
运行一下
public class ConditionQueueDemo {
private static volatile AtomicInteger atomicInteger = new AtomicInteger(0);
static Integer threadNum = 15;
public static void main(String[] args) {
ConditionQueue conditionQueue = new ConditionQueue();
// 压数据
CyclicBarrier putCyclicBarrier = new CyclicBarrier(threadNum, () -> {
System.out.println("put finish");
});
for (int i = 0; i < threadNum; i++) {
new Thread(() -> {
try {
int value = atomicInteger.incrementAndGet();
conditionQueue.put(value);
System.out.println("put: " + JSON.toJSONString(conditionQueue.items) +
", put value:" + value);
Thread.sleep(100);
try {
putCyclicBarrier.await();
} catch (BrokenBarrierException e) {
throw new RuntimeException(e);
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}).start();
}
// 取数据
CyclicBarrier takeCyclicBarrier = new CyclicBarrier(threadNum, () -> {
System.out.println("task finish");
});
for (int i = 0; i < threadNum; i++) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
new Thread(() -> {
try {
Object taskValue = conditionQueue.take();
System.out.println("task: " + JSON.toJSONString(conditionQueue.items) +
", taskValue:" + taskValue);
takeCyclicBarrier.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
} catch (BrokenBarrierException e) {
throw new RuntimeException(e);
}
}).start();
}
System.out.println("End.");
}
}
运行结果
put: [1,2,3,4,5,6,7,8,9,10], put value:2
put: [1,2,3,4,5,6,7,8,9,10], put value:1
put: [1,2,3,4,5,6,7,8,9,10], put value:7
put: [1,2,3,4,5,6,7,8,9,10], put value:9
put: [1,2,3,4,5,6,7,8,9,10], put value:4
put: [1,2,3,4,5,6,7,8,9,10], put value:5
put: [1,2,3,4,5,6,7,8,9,10], put value:10
put: [1,2,3,4,5,6,7,8,9,10], put value:3
put: [1,2,3,4,5,6,7,8,9,10], put value:6
put: [1,2,3,4,5,6,7,8,9,10], put value:8
put: [11,2,3,4,5,6,7,8,9,10], put value:11
task: [11,2,3,4,5,6,7,8,9,10], taskValue:1
task: [11,12,3,4,5,6,7,8,9,10], taskValue:2
put: [11,12,3,4,5,6,7,8,9,10], put value:12
task: [11,12,null,4,5,6,7,8,9,10], taskValue:3
put: [11,12,13,4,5,6,7,8,9,10], put value:13
task: [11,12,13,14,5,6,7,8,9,10], taskValue:4
put: [11,12,13,14,5,6,7,8,9,10], put value:14
put: [11,12,13,14,15,6,7,8,9,10], put value:15
task: [11,12,13,14,15,6,7,8,9,10], taskValue:5
put finish
task: [11,12,13,14,15,null,7,8,9,10], taskValue:6
task: [11,12,13,14,null,null,7,8,9,10], taskValue:15
task: [11,12,13,null,null,null,7,8,9,10], taskValue:14
task: [11,12,null,null,null,null,7,8,9,10], taskValue:13
task: [11,null,null,null,null,null,7,8,9,10], taskValue:12
task: [null,null,null,null,null,null,7,8,9,10], taskValue:11
task: [null,null,null,null,null,null,7,8,9,null], taskValue:10
task: [null,null,null,null,null,null,7,8,null,null], taskValue:9
task: [null,null,null,null,null,null,7,null,null,null], taskValue:8
End.
task: [null,null,null,null,null,null,null,null,null,null], taskValue:7
task finish
核心实现
条件信号的阻塞队列核心
static class ConditionQueue {
Lock lock = new ReentrantLock();
final Condition notFull = lock.newCondition();
final Condition notEmpty = lock.newCondition();
final Integer QUEUE_LENGTH = 10;
final Object[] items = new Object[QUEUE_LENGTH];
volatile AtomicInteger count = new AtomicInteger(0);
volatile AtomicInteger putIndex = new AtomicInteger(0);
public void put(Object x) throws InterruptedException {
lock.lock();
try {
// put 时判断是否已经满了
// 则线程在 notFull 条件上排队阻塞
while (count.get() == QUEUE_LENGTH) {
notFull.await();
}
int index = putIndex.getAndIncrement() % QUEUE_LENGTH;
items[index] = x;
count.incrementAndGet();
// put 成功之后,队列中有元素
// 唤醒在 notEmpty 条件上排队阻塞的线程
notEmpty.signal();
} finally {
lock.unlock();
}
}
public Object take() throws InterruptedException {
lock.lock();
try {
// take 时,发现为空
// 则线程在 notEmpty 的条件上排队阻塞
while (count.get() == 0) {
notEmpty.await();
}
// 置空一个元素
Integer takePtr = putIndex.get() % QUEUE_LENGTH;
Object x = items[takePtr];
for(;;){
if (x == null){
takePtr = takePtr - 1 >= 0 ? takePtr - 1 : takePtr - 1 + 10;
x = items[takePtr];
continue;
}
items[takePtr] = null;
break;
}
count.decrementAndGet();
// take 成功,队列不可能是满的
// 唤醒在 notFull 条件上排队阻塞的线程
notFull.signal();
return x;
} finally {
lock.unlock();
}
}
}