62,628
社区成员
发帖
与我相关
我的任务
分享package org.imzhs.learn.test;
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;
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.");
}
}
输出:
1234123412341234123412341234123412341234123412341234123412341234123412341234123412341234123412341234123412341234123412341234123412341234123412341234123412341234123412341234123412341234123412341234123412341234123412341234123412341234123412341234123412341234123412341234123412341234123412341234123412341234123412341234123412341234123412341234123412341234123412341234123412341234123412341234123412341234
执行完毕,耗时 31ms.
当然,这种实现有一个问题,就是会造成storge部分空间浪费(为了维持状态的稳定),以及会多创建一个用来重置状态的monitor生产者。但是这种方式的锁代价相对比较小,执行速度也会比严格同步要快。
如果有好的建议,欢迎提出~