import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
/**
 * 有四个生产者线程A、B、C、D,分别向一个固定大小为11的storage数组(int storage[]=new int[15];)中插入数据。
 * 线程A只能插入数字1,线程B只能插入数字2,线程C只能插入数字3,线程D只能插入数字4,插入的数字顺序为1,2,3,4,1,2,3,4,1……。
 * 同时有一个消费者线程E从storage数组中取出数字(每次取一个,取出来之后就打印这个数字)。
 * 要求打印数字的顺序为插入顺序(每个线程插入100次各自的数字),完成全部入库出库操作耗时控制在200毫秒以内。
 * @author user
 *
 */
public class App {
	public static AtomicInteger state = new AtomicInteger(0); //用来保证生产顺序的状态量
	public static int[] storage = new int[11];  //生产线
	public static AtomicInteger currentStorageIndex = new AtomicInteger(0); //生产线指针
	public static ReentrantLock syncLock = new ReentrantLock(false); //用来保证消费者消费与生产者生产进行同步的lock
	public static Condition consumeCondition = syncLock.newCondition(); //消费者同步信号量
	public static Condition productCondition = syncLock.newCondition(); //生产者同步信号量
	public static CountDownLatch latch = new CountDownLatch(5);  //用来监视所有生产者线程是否执行完毕的latch

	//消费者
	public static class Consumer implements Runnable {
		public AtomicBoolean isStarted = new AtomicBoolean(false);

		@Override
		public void run() {
			while (latch.getCount() > 0) {
				try {
					isStarted.set(true);
					syncLock.lock();
					//等待生产线变满
					consumeCondition.await();
					for (int i = 0; i < storage.length; i++) {
						if (storage[i] != 0) {
							System.out.print(storage[i]);
							storage[i] = 0;
						}
					}
					//重置生产线指针
					currentStorageIndex.set(0);;
					productCondition.signalAll();
				} catch (InterruptedException e) {
				} finally {
					syncLock.unlock();
				}
			}
		}
	}

	//生产者
	public static class Productor implements Runnable {
		public int expect; //前置量,状态为该值,才会加入生产线
		public int number; //生产量,即加入生产线的量,生产完毕会将状态量设置为该量
		public int repeat; //重试次数

		@Override
		public void run() {
			while (repeat > 0) {
				int currentState = state.get();
				if (expect == currentState) {
					//双重校验
					if (state.get() == currentState) {
						try {
							syncLock.lock();
							//CAS,保证多线程环境下的state并发修改的happends-before(1,2,3,4,0顺序)
							if (state.compareAndSet(expect, number)) {
								int index = currentStorageIndex.incrementAndGet();
								if (index >= storage.length) {
									if(index == storage.length + latch.getCount() - 1){ 
										//此时所有生产者会处于停滞状态,需要启动通知消费者进行消费
										consumeCondition.signalAll();
									}
									//等待消费者消费
									productCondition.await();
								} else {
									repeat--;
									storage[index] = expect;
								}
							}
						} catch (InterruptedException e) {
						} finally {
							syncLock.unlock();
						}
					}
				} else {
					Thread.yield();
				}
			}
			latch.countDown();
		}

		public Productor(int expect, int number, int repeat) {
			this.expect = expect;
			this.number = number;
			this.repeat = repeat;
		}
	}

	public static void main(String[] args) throws InterruptedException {
		long sartTime = System.currentTimeMillis();
		
		//构造生产者实例
		Productor p1 = new Productor(0, 1, 100);
		Productor p2 = new Productor(1, 2, 100);
		Productor p3 = new Productor(2, 3, 100);
		Productor p4 = new Productor(3, 4, 100);

		Productor monitor = new Productor(4, 0, 100);

		//构造所有消费者实例
		Consumer consumer = new Consumer();
		//创建并启动消费者线程
		Thread tConsumer = new Thread(consumer);
		tConsumer.start();

		//等待消费者启动完毕
		while (!consumer.isStarted.get()) {
			Thread.yield();
		}
		
		//启动所有生产者
		new Thread(p1).start();
		new Thread(p2).start();
		new Thread(p3).start();
		new Thread(p4).start();

		new Thread(monitor).start();
		
		//等待生产者执行完毕
		latch.await();
		//让消费者进行最后一次消费
		syncLock.lock();
		consumeCondition.signalAll();
		syncLock.unlock();
		//等待消费者执行完毕
		tConsumer.join();
		
		long endTime = System.currentTimeMillis();
		
		System.out.println("\n执行完毕,耗时 " + (endTime - sartTime) + "ms.");
	}
}