【并发编程】- 使用Semaphore、ReentrantLock实现多生产者、多消费者模式

244 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 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 生产了 数据
......