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."); } }
一个线程题
转载上一篇:Java实现阻塞队列的两种方式
下一篇:Java中的线程(一)
提问和评论都可以,用心的回复会被更多人看到
评论
发布评论
相关文章
-
一个线程,从“生”到“死”经历的过程
通用的线程生命周期总体上可以分为五个状态:初始状态、可运行状态、运行状态、休眠状态和终止状态。
Java 生命周期 休眠状态 线程生命周期