生产者消费者模式--java

首先我们说一下什么是线程安全问题
场景:现在银行账户有5000元、有两个线程t1和t2、由于这两个线程是异步执行的取款操作、有可能t1线程取款1000、还没等更新账户、t2就已经也取款1000、这样导致t1线程取款后、余额还剩4000、t2线程取款后、余额还剩4000、这样就导致了t1和t2两个线程不安全问题。简单来说、需要同步线程的时候却出现了异步、这就导致线程不安全。
案例(生产者消费者模式)
1、生产者和消费者应该操作共享资源
2、使用一个或多个线程来表示生产者
3、使用一个或多个线程来表示消费者
为什么生产者不直接把数据给消费者、而是先把数据存放到共享资源中、然后消费者再从共享资源取出数据。
从面相对象的角度来说:我们要实现低耦合的代码
——————————————————————————————————————
我们创建一个生产者我么在这里插入图片描述
我们创建一个消费者
我们创建一个消费者
创建一个公共资源区
在这里插入图片描述
部分打印结果如下
在这里插入图片描述
下面我们来分析一下打印结果
当生产者生产一个春哥-男时、这时候消费者还没有来得及取出来、然后生产者又往共享资源区存入了凤姐结果把春哥覆盖掉了、这时候消费者刚好取出凤姐-男。
问题:出现了性别紊乱的问题
解决方案:只要保证生产者在生产姓名和性别的过程中保持同步、中间消费者不能来取走。
等待唤醒机制
wait():执行该方法的线程对象释放同步锁、,jvm把线程放到等待池中、等待其他线程来唤醒该线程。
notify():执行该方法的线程随机唤醒一个在等待池中的线程(等待池中的线程并不能执行代码)、把线程放到锁池中。
上述方法只能被同步监听锁对象来调用、否则报异常illegalMonitorStateException
假设a线程和b线程共同操作一个x对象,a、b线程可以通过x对象的wait()方法和notify()方法进行通信:
1、当a线程执行x对象的同步方法是、a线程室友x的对象锁,b线程没有执行机会、b线程在x对象的锁池中等待
2、a线程在同步方法中执行x.wait()方法是、a线程释放x对象锁、a线程进入等待池
3、在x对象的锁池中等待b线程获取x的对象锁、执行x对象的另一个同步方法
4、b线程在同步方法中执行x.notify()时、jvm把a线程从x对象的等待池移到锁池中、随时等待获取锁
5、b线程执行完同步方法释放锁、a线程获得锁、执行同步方法


/**
 * 创建公共资源
 */
public class ShareResource {
    private String name;//性名
    private String gender;//性别
    private boolean isEmpty = true;//判断资源对象是否为空

    //向生产者提供一个生产的方法
    public synchronized void push(String name, String gender) {
        try {
            //共享资源区初始值为空、if条件不成立
            while (!isEmpty) {
                //isEmpty为false、即共享资源区为部位空、不在生产
                // 等待消费者来获取
                //将线程Processor放入等待池、只能被其他线程唤醒
                this.wait();
            }
            //生产开始
            this.name = name;
            Thread.sleep(500);
            this.gender = gender;
            //生产结束
            //共享资源区不为空
            isEmpty = false;
            this.notify();//唤醒消费者消费
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //向消费者提供一个消费的方法
    public synchronized void pull() {
        try {
            //isEmpty为空、进入等待池、等待生产者生产
            while (isEmpty) {
                this.wait();
            }
            //消费开始
            Thread.sleep(500);
            System.out.println(this.name + "-" + this.gender);
            //消费结束
            isEmpty = true;
            this.notify();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
/**
 * 创建消费者
 */
public class Consumer implements Runnable {
    private ShareResource resource = null;

    public Consumer(ShareResource resource) {
        this.resource = resource;
    }

    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            resource.pull();
        }
    }
}
/**
 * 创建生产者
 */
public class Producer implements Runnable {
    private ShareResource resource = null;

    public Producer(ShareResource resource) {
        this.resource = resource;
    }
    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            //先生产春哥-男、在生产凤姐-女
            if (i % 2 == 0) {
                resource.push("春哥", "男");
            } else {
                resource.push("凤姐", "女");
            }
        }
    }
}
public class App {
    public static void main(String[] args) {
        //创建一个公共资源对象
        ShareResource resource = new ShareResource();
        //启动生产者线程
        new Thread(new Producer(resource)).start();
        //启动消费者线程
        new Thread(new Consumer(resource)).start();
    }
}

我们来分析一下等待唤醒机制
1、首先生产者消费者启动线程、异步进入临界区(公用资源区)。
2、消费者判断临界区为空、进入等待池等待。生产者判断临界区为空、开始生产。
3、生产者生产完毕后、临界区资源isEmpty = false、生产者唤醒消费者线程进入锁池、随时拿住对象锁来消费临界区资源。然后自己又要生产、开始判断临界区、进入等待池。
4、消费者消费资源、然后isEmpty = true、消费者唤醒生产者。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值