一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第10天,点击查看活动详情。
使用Semaphore、ReentrantLock实现多生产者/多消费者模式
实现代码如下:
@Slf4j
public class RepastService {
volatile private Semaphore produceSemaphore = new Semaphore(10);
volatile private Semaphore consumeSemaphore = new Semaphore(20);
volatile private ReentrantLock lock = new ReentrantLock();
volatile private Condition produceCondition = lock.newCondition();
volatile private Condition consumeCondition = lock.newCondition();
volatile private Object[] producePosition = new Object[4];
private boolean isEmpty() {
boolean isEmpty = true;
for (int i = 0; i < producePosition.length; i++) {
if (producePosition[i] != null) {
isEmpty = false;
break;
}
}
if (isEmpty == true) {
return true;
} else {
return false;
}
}
private boolean isFull() {
boolean isFull = true;
for (int i = 0; i < producePosition.length; i++) {
if (producePosition[i] == null) {
isFull = false;
break;
}
}
return isFull;
}
public void set() {
try {
produceSemaphore.acquire();
lock.lock();
while (isFull()) {
log.info("生产者在等待!");
produceCondition.await();
}
for (int i = 0; i < producePosition.length; i++) {
if (producePosition[i] == null) {
producePosition[i] = "数据";
log.info("线程名:{} 生产了 {}", Thread.currentThread().getName(), producePosition[i]);
break;
}
}
consumeCondition.signalAll();
lock.unlock();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
produceSemaphore.release();
}
}
public void get() {
try {
consumeSemaphore.acquire();
lock.lock();
while (isEmpty()) {
log.info("消费者在等待!");
consumeCondition.await();
}
for (int i = 0; i < producePosition.length; i++) {
if (producePosition[i] != null) {
log.info("线程名:{} 消费了 {} ", Thread.currentThread().getName(), producePosition[i]);
producePosition[i] = null;
break;
}
}
produceCondition.signalAll();
lock.unlock();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
consumeSemaphore.release();
}
}
}
生产者线程代码如下:
public class ThreadP implements Runnable {
private RepastService repastService;
public ThreadP(RepastService repastService){
super();
this.repastService=repastService;
}
@Override
public void run() {
repastService.set();
}
}
消费者线程代码如下:
public class ThreadC implements Runnable {
private RepastService service;
public ThreadC(RepastService service){
super();
this.service=service;
}
@Override
public void run() {
service.get();
}
}
运行类代码如下:
public class RepastController {
public static void main(String[] args) throws InterruptedException {
RepastService service = new RepastService();
ThreadP[] threadPS = new ThreadP[20];
ThreadC[] threadCS = new ThreadC[20];
for (int i = 0; i < 20; i++) {
threadPS[i] = new ThreadP(service);
threadCS[i] = new ThreadC(service);
}
Thread.sleep(3000);
for (int i = 0; i < 20; i++) {
new Thread(threadPS[i]).start();
new Thread(threadCS[i]).start();
}
}
}
程序运行结果如下:
17:10:34.946 [Thread-1] INFO com.ozx.concurrentprogram.semaphore.service.RepastService - 消费者在等待!
17:10:34.955 [Thread-0] INFO com.ozx.concurrentprogram.semaphore.service.RepastService - 线程名:Thread-0 生产了 数据
17:10:34.960 [Thread-3] INFO com.ozx.concurrentprogram.semaphore.service.RepastService - 线程名:Thread-3 消费了 数据
17:10:34.960 [Thread-5] INFO com.ozx.concurrentprogram.semaphore.service.RepastService - 消费者在等待!
17:10:34.960 [Thread-14] INFO com.ozx.concurrentprogram.semaphore.service.RepastService - 线程名:Thread-14 生产了 数据
17:10:34.961 [Thread-12] INFO com.ozx.concurrentprogram.semaphore.service.RepastService - 线程名:Thread-12 生产了 数据
17:10:34.962 [Thread-8] INFO com.ozx.concurrentprogram.semaphore.service.RepastService - 线程名:Thread-8 生产了 数据
17:10:34.962 [Thread-21] INFO com.ozx.concurrentprogram.semaphore.service.RepastService - 线程名:Thread-21 消费了 数据
17:10:34.962 [Thread-22] INFO com.ozx.concurrentprogram.semaphore.service.RepastService - 线程名:Thread-22 生产了 数据
17:10:34.963 [Thread-6] INFO com.ozx.concurrentprogram.semaphore.service.RepastService - 线程名:Thread-6 生产了 数据
17:10:34.964 [Thread-26] INFO com.ozx.concurrentprogram.semaphore.service.RepastService - 生产者在等待!
17:10:34.964 [Thread-4] INFO com.ozx.concurrentprogram.semaphore.service.RepastService - 生产者在等待!
17:10:34.964 [Thread-19] INFO com.ozx.concurrentprogram.semaphore.service.RepastService - 线程名:Thread-19 消费了 数据
17:10:34.964 [Thread-23] INFO com.ozx.concurrentprogram.semaphore.service.RepastService - 线程名:Thread-23 消费了 数据
17:10:34.967 [Thread-13] INFO com.ozx.concurrentprogram.semaphore.service.RepastService - 线程名:Thread-13 消费了 数据
17:10:34.968 [Thread-20] INFO com.ozx.concurrentprogram.semaphore.service.RepastService - 线程名:Thread-20 生产了 数据
17:10:34.969 [Thread-32] INFO com.ozx.concurrentprogram.semaphore.service.RepastService - 线程名:Thread-32 生产了 数据
17:10:34.970 [Thread-36] INFO com.ozx.concurrentprogram.semaphore.service.RepastService - 线程名:Thread-36 生产了 数据
......