03多线程-用ReentrantLock实现生产者和消费者模式

本文介绍了如何使用Java的ReentrantLock类以及Condition接口实现生产者消费者模式,包括变量定义、线程同步和互斥控制,以及使用await和signal进行线程间通信。
摘要由CSDN通过智能技术生成

一句话导读

        ReentrantLock重入锁,是实现Lock接口的一个类,也是在实际编程中使用频率很高的一个锁,支持重入性,表示能够对共享资源重复加锁,即当前线程获取该锁再次获取不会被阻塞。在java关键字synchronized隐式支持重入性,synchronized通过获取自增,释放自减的方式实现重入。与此同时,ReentrantLock还支持公平锁和非公平锁两种方式。

目录

一句话导读

一、首先定义生产者

1.变量定义

2.生产面包方法

3.线程接口实现

二、其次定义消费者

1.变量的定义

2.消费面包的方法

3.实现线程接口

三、最后定义主方法


下面我们了解下如何通过ReentrantLock实现生产者和消费者模式吧,线程间的交互需要用到Condition的await、signal;

一、首先定义生产者

1.变量定义

        在变量定义的时候,首先定义了一个容器和这个容器的上限:List breads; int maxSize;生产好的面包则放到breads中,达到上限maxSize则停止生产。另外定义了一个锁ReentrantLock lock,在线程操作breads的时候,需要通过lock来做到互斥。通过定义两个锁信号来做到线程间的通讯,当容器满了在Condition full需要等待。当容器空了,则Condition empty进入等待

2.生产面包方法

        首先获取锁lock.lock();然后判断容器breads是否满了,如果满了则当前线程等待full.await();如果容器没有满,则可以生成面包,breads.add(bread);并且唤醒消费者empty.signalAll();

3.线程接口实现

        通过Runnable接口,实现run方法,循环调用生产面包方法

import com.rainy.distributlock.producerAndConsumer.Bread;
import com.rainy.distributlock.producerAndConsumer.blockingQueue.BreadStore;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 生产者
 */
public class Producer implements Runnable {
    //锁
    private ReentrantLock lock;
    //容器满了的信号
    private Condition full;
    //容器空了的信号
    private Condition empty;
    //容器
    private List<Bread> breads;
    //容器最大容量
    private int maxSize;
    //计数器
    private AtomicInteger count = new AtomicInteger(0);

    //构造方法
    public Producer(ReentrantLock lock, Condition full, Condition empty, List<Bread> breads, int maxSize) {
        this.lock = lock;
        this.full = full;
        this.empty = empty;
        this.breads = breads;
        this.maxSize = maxSize;
    }

    //生产面包
    public void produce() {
        //获取锁
        lock.lock();
        try {
            //如果容器满了,等待
            if (breads.size() == maxSize) {
                //当前线程等待
                System.out.println(Thread.currentThread().getName() + "容器已满,等待");
                full.await();
                System.out.println(Thread.currentThread().getName() + "生产面包被唤醒");
            //没有满则生产面包
            }else {
                Bread bread = new Bread(UUID.randomUUID().toString(), Thread.currentThread().getName() + "-" + count.getAndIncrement());
                breads.add(bread);
                System.out.println(Thread.currentThread().getName() + "生产了面包:" + bread);
                //唤醒等待的消费者
                empty.signalAll();
//                Thread.sleep(1000);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            System.out.println(Thread.currentThread().getName() + "释放锁");
            lock.unlock();
        }
    }

    @Override
    public void run() {
        while (true) {
            produce();
        }
    }
}

二、其次定义消费者

1.变量的定义

        定义锁、信号条件以及容器。通过构造方法,将变量的值初始化,生产者的变了也是通过构造方法初始化的,这样就可以将所有的变量共享了

2.消费面包的方法

        首先获取锁lock.lock();当容器为空的时候breads.isEmpty(),则不能再消费,消费线程等待,empty.await();当容器不为空,则获取面包并从容器中移除,breads.remove(0);并发出继续生产面包的信号:full.signalAll();

3.实现线程接口

        通过Runnable接口实现run方法,循环调用消费面包方法

import com.rainy.distributlock.producerAndConsumer.Bread;

import java.util.List;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class Consumer implements Runnable {
    private ReentrantLock lock;
    private Condition full;
    private Condition empty;
    private List<Bread> breads;

    //构造方法
    public Consumer(ReentrantLock lock, Condition full, Condition empty, List<Bread> breads) {
        this.lock = lock;
        this.full = full;
        this.empty = empty;
        this.breads = breads;
    }

    //生产面包
    public void consumer() {
        lock.lock();
        try {
            if (breads.isEmpty()) {
                System.out.println("没有面包了");
                empty.await();
                System.out.println("开始生产面包");
            } else {
                Bread bread = breads.remove(0);
                System.out.println(Thread.currentThread().getName() + "-" + bread.getName());
                full.signalAll();
                Thread.sleep(1000);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    @Override
    public void run() {
        while (true) {
            System.out.println(Thread.currentThread().getName() + "释放锁");
            consumer();
        }
    }
}

三、最后定义主方法

        首先定义共享变量,锁ReentrantLock reentrantLock;容器List list;最大容量 int maxSIze; 容器满条件Condition full;容器空条件Condition empty;

        然后定义生产者线程,并将变量赋值到到生产者中

        再定义两个消费者线程,并将变量赋值到消费者中

        最后启动各个线程,即可实现生产者和消费者模式了。

import com.rainy.distributlock.producerAndConsumer.Bread;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class MainProcess {
    public static void main(String[] args) {
        ReentrantLock reentrantLock = new ReentrantLock();
        List<Bread> list = new ArrayList<>();
        int maxSize = 100;
        Condition full = reentrantLock.newCondition();
        Condition  empty = reentrantLock.newCondition();

        Producer producer = new Producer(reentrantLock,full,empty,list,maxSize);
        Thread producerThread = new Thread(producer);
        producerThread.setName("生产者");
        producerThread.start();

        Consumer consumer = new Consumer(reentrantLock,full,empty,list);
        Thread consumerThread = new Thread(consumer);
        consumerThread.setName("消费者1");
        consumerThread.start();

        Consumer consumer2 = new Consumer(reentrantLock,full,empty,list);
        Thread consumerThread2 = new Thread(consumer2);
        consumerThread2.setName("消费者2");
        consumerThread2.start();
    }
}

  • 32
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值