单个生产者Producer、消费者Consumer之间的线程通信

本篇博文介绍的是多线程中线程间通信入门的实例。

  • 使用线程P表示消费数据线程,使用线程C表示生产数据线程。如果程序开始时,线程C抢到了CPU执行权,发现isProduce为false即没有数据供其消费,便调用Lock.wait(),使得C线程进入了锁对象LOCK线程等待池中(注意wait()方法是会释放锁对象的);此时P线程抢到了CPU执行权,发现isProduce为false,就会去生产数据,生产完数据后,调用Lock.notify(),唤醒在锁对象LOCK线程等待池中的线程(这里是C线程),使得C线程进入LOCK锁的锁池中,并且将isProduce置为true,表示已经生产了数据;下一步C线程抢到了CPU执行权,发现isProduce为true,便会消费数据,并调用LOCK.notify()唤醒P线程重新生产数据,并将isProduce置为false,表示没有数据了。

就这样,一直循环下去,生产数据线程与消费数据线程一直交替运行,不会出现任何错误!

注:如果对博文中提及的线程等待池、锁池及sleep()wait()不熟悉的读者,可以参考下面这篇文章:点击一下
同时,如果是多个Producer和多个Consumer之间的通信,使用上面的代码会发生假死锁的现象,有机会我也会写一篇博客介绍这种情况。有兴趣的读者,可以关注博主!!!

下面是代码部分:


```java
package exercise01.src.com.yyh.day08;
public class ProduceConsumeVersion2 {
    private final Object LOCK = new Object();
    private int i = 0;
    private volatile boolean isProduce = false; //false表示没有生产,true表示已经生产了

    //生产数据
    private void produce(){
        synchronized (LOCK){
            if(isProduce){ //isProduce为true,表示已经生产过了,就进入等待状态,
                try {
                    //调用wait方法后,拥有该锁的生产数据线程进入等待池中,而等待池中的线程不会去竞争锁的;
                    // 只有【锁对象】调用了notify或notifyAll方法,才使得该锁对象上的等待池中的线程进入锁池中,
                    // 然后去竞争锁对象
                    LOCK.wait();//wait()是会释放锁对象的
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }else { //如果没有生产的话,就要生产数据了,然后通知消费线程来消费数据
                i++;
                System.out.println("P--> "+i); //生产数据
                LOCK.notify(); //唤醒消费数据的线程
                isProduce = true;//表示已经生产,好让消费线程进行判断
            }
        }
    }
    //消费数据
    private void consume(){
        synchronized (LOCK){
            if(!isProduce){ //如果没有生产,消费数据线程就会进入LOCK锁对象的线程等待池中
                try {
                    LOCK.wait();//wait()是会释放锁对象的
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }else {
                System.out.println("C--> "+i); //消费数据
                LOCK.notify(); //消费完了以后,就要唤醒在锁对象LOCK的等待池线程,即生产数据线程
                isProduce = false;  //消费完以后,唤醒生产数据线程,同时将标志置为false,表示没生产
            }
        }
    }

    public static void main(String[] args) {
        ProduceConsumeVersion2 pc2 = new ProduceConsumeVersion2();
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    pc2.consume();
                }
            }
        },"C线程").start();
        new Thread("P线程"){
            @Override
            public void run() {
                while (true) {
                    pc2.produce();
                }
            }
        }.start();

    }

}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
单个生产者单个消费者的场景中,我们可以使用互斥锁来保证进程同步。具体实现如下: 假设我们有一个缓冲区,大小为N,初始时为空。生产者可以向缓冲区中插入数据,消费者可以从缓冲区中取出数据。 生产者的伪代码: ``` while (true) { // 产生数据 data = produce_data(); // 获取互斥锁 acquire_lock(mutex); // 如果缓冲区已满,等待 while (count == N) { wait(producer_cv, mutex); } // 插入数据到缓冲区中 buffer[in] = data; in = (in + 1) % N; count++; // 释放互斥锁 release_lock(mutex); // 唤醒消费者 signal(consumer_cv); } ``` 消费者的伪代码: ``` while (true) { // 获取互斥锁 acquire_lock(mutex); // 如果缓冲区为空,等待 while (count == 0) { wait(consumer_cv, mutex); } // 从缓冲区中取出数据 data = buffer[out]; out = (out + 1) % N; count--; // 释放互斥锁 release_lock(mutex); // 处理数据 consume_data(data); // 唤醒生产者 signal(producer_cv); } ``` 其中,`mutex`是一个互斥锁,`producer_cv`和`consumer_cv`是两个条件变量。`acquire_lock`和`release_lock`是获取和释放互斥锁的函数。`wait`和`signal`是条件变量的等待和唤醒函数。 在生产者消费者的伪代码中,通过互斥锁来保证同一时间只有一个进程能够访问缓冲区。当缓冲区已满时,生产者会等待消费者消费数据,当缓冲区为空时,消费者会等待生产者生产数据。通过条件变量来实现等待和唤醒的操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值