package com.elab.example.springbootdemo.demo;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created by dengcheng on 2018/8/17.
 */
public class MyBlockingArray<E> {
    private Logger logger = LoggerFactory.getLogger(MyBlockingArray.class);
    E[] datas;
    int takeIndex = -1;
    int offerIndex = -1;
    int count = 0;
    int size;
    private ReentrantLock lock = new ReentrantLock();
    private Condition notEmpty = lock.newCondition();
    private Condition notFull = lock.newCondition();

    public MyBlockingArray(int size) {
        datas = (E[]) new Object[size];
        this.size = size;
    }

    public boolean offer(E e) {
        try {
            lock.lockInterruptibly();

            if (count == size) {
                logger.info(" 阻塞队列满啦.");
                notFull.await();
            }

            if (datas.length > 0)
                notEmpty.signal();

            ++offerIndex;
            datas[offerIndex] = e;
            ++count;
            if ((offerIndex + 1) == datas.length)
                offerIndex = -1;

            return true;
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            lock.unlock();
        }
        return false;
    }

    public E take() {
        try {
            lock.lockInterruptibly();

            if (count == 0) {
                logger.info(" 阻塞队列空了.");
                notEmpty.await();
            }
            ++takeIndex;

            E e = datas[takeIndex];
            --count;
            if ((takeIndex + 1) == datas.length)
                takeIndex = -1;
            return e;
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            lock.unlock();
        }
        return null;
    }

    public static void main(String[] args) {
        final MyBlockingArray<Integer> array = new MyBlockingArray<Integer>(10);
        new Thread(new Runnable() {
            public void run() {
                int i = 0;
                while (true) {
                    i++;
                    array.offer(i);
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

            }
        }).start();

        new Thread(new Runnable() {
            public void run() {
                while (true) {
                    Integer data = array.take();
                    if (data == null)
                        break;
                    System.out.println(data);
                }

            }
        }).start();

    }
}