JUC.Condition实现阻塞队列

62 阅读3分钟

# 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();
        }
    }
}