生产者消费者_测试

/*
 * 模拟生产者和消费者:
 *     思路:
 *         资源类:包子类
 *         生产者线程:SetThread
 *         消费者线程:GetThread
 *         测试类:Demo6
 *
 * 我们按照思路写出了代码,发现了有null和0这样的数据
 *      因为线程是抢占式争夺cpu的执行权的,有可能消费者线程先抢到了cpu的执行权,那么这个时候
 *     生产者线程还没有生产出来,所以就出现了null  和  0 这样的数据。
 *     很明显这样是不对的,应该是生产者先生产,然后消费者在消费。
 *
 *     为了让效果更明显一些,我加入循环和判断,给出不同的值
 * 结果又出现了新的问题:
 *         同一个包子被消费了多次
 *             因为cpu的一点点的执行权,就足够执行这个代码很多次。
 *          包子和价格不匹配了
 *             因为线程运行的随机性
 *
 * 说明存在线程安全问题:
 *         是否是多线程:是
 *         是否有共享数据:有
 *         是否有多条语句操作共享数据:有
 *
 *     解决方案:
 *         上锁
 *         注意:
 *             不同种类的线程都要加锁,而且必须是同一把锁    
 *
 * 线程安全问题通过加锁是解决了,但是还存在一个问题:
 *     如果是消费者先抢到了cpu的执行权,就会去消费,但是这个时候生产者还没有生产,消费者消费的数据就是默认值 null  和  0
 *     应该等生产者生产之后再消费。这样才有意义。
 *     如果生产者先抢到了执行权,就去生产,但是它生产完成后有肯能还拥有执行权,它就会继续生产,这个也是有问题的。
 *     应该是生产完后等消费者把它消费掉后,再继续生产。
 *
 * 正常的情况:
 *         生产者:
 *             先看是否有数据了,如果有,就等着消费者来消费。如果没有,就生产。生产完后通知消费者来消费包子。。。
 *         消费者:
 *             先看是否有数据,如果有,就消费。如果没有,就等待,通知生产者去生产。
 *
 * 为了解决这个问题,java就提供了一种机制:  等待唤醒机制。
 *
 *   等待唤醒机制:
 *       Object类中有3个方法:
 *           public final void wait()
            public final void notify()
            public final void notifyAll()
    为什么这几个方法不在Thread中?
        因为这个方法的调用是通过锁对象调用的,而我们同步代码块的锁对象可以是任意对象,
        所以,这些方法就定义再Object中。
 * */
public class Demo6 {
    public static void main(String[] args) {
        //创建资源对象
        BaoZi bz = new BaoZi();
        //创建生产者和消费者
        SetThread st = new SetThread(bz);
        GetThread gt = new GetThread(bz);
        
        //创建线程
        Thread t1 = new Thread(st,"成产者");
        Thread t2 = new Thread(gt,"消费者");
        
        t2.setPriority(10);
        
        //启动线程
        t2.start();
        t1.start();
    }
}
package com.momo.demo;

public class GetThread implements Runnable {
    private BaoZi bz;

    public GetThread(BaoZi bz) {
        this.bz = bz;
    }

    @Override
    public void run() {
        // BaoZi bz = new BaoZi();
        while (true) {
            synchronized (bz) {
                System.out.println(bz.name + ":" + bz.price);
                // System.out.println(Thread.currentThread().getName()+"消费了这个包子");
            }
        }
    }
}
package com.momo.demo;

public class SetThread implements Runnable {
    private BaoZi bz;
    private int i = 0;

    public SetThread(BaoZi bz) {
        this.bz = bz;
    }

    @Override
    public void run() {
        // BaoZi bz = new BaoZi();
        while (true) {
            synchronized (bz) {

                if (i % 2 == 0) {
                    bz.name = "肉包子";
                    bz.price = 2;
                    // System.out.println(Thread.currentThread().getName()+"生产了一个肉包子");
                } else {
                    bz.name = "菜包子";
                    bz.price = 1;
                    // System.out.println(Thread.currentThread().getName()+"生产了一个菜包子");
                }
                // System.out.println(Thread.currentThread().getName()+"生产了一个包子");
                i++;
            }
        }
    }

}
package com.momo.demo;

public class BaoZi {
    String name;
    int price;
}


package com.momo.demo;
/*
 * 模拟生产者和消费者:
 *     思路:
 *         资源类:包子类
 *         生产者线程:SetThread
 *         消费者线程:GetThread
 *         测试类:Demo6
 *
 * 我们按照思路写出了代码,发现了有null和0这样的数据
 *      因为线程是抢占式争夺cpu的执行权的,有可能消费者线程先抢到了cpu的执行权,那么这个时候
 *     生产者线程还没有生产出来,所以就出现了null  和  0 这样的数据。
 *     很明显这样是不对的,应该是生产者先生产,然后消费者在消费。
 *
 *     为了让效果更明显一些,我加入循环和判断,给出不同的值
 * 结果又出现了新的问题:
 *         同一个包子被消费了多次
 *             因为cpu的一点点的执行权,就足够执行这个代码很多次。
 *          包子和价格不匹配了
 *             因为线程运行的随机性
 *
 * 说明存在线程安全问题:
 *         是否是多线程:是
 *         是否有共享数据:有
 *         是否有多条语句操作共享数据:有
 *
 *     解决方案:
 *         上锁
 *         注意:
 *             不同种类的线程都要加锁,而且必须是同一把锁    
 *
 * 线程安全问题通过加锁是解决了,但是还存在一个问题:
 *     如果是消费者先抢到了cpu的执行权,就会去消费,但是这个时候生产者还没有生产,消费者消费的数据就是默认值 null  和  0
 *     应该等生产者生产之后再消费。这样才有意义。
 *     如果生产者先抢到了执行权,就去生产,但是它生产完成后有肯能还拥有执行权,它就会继续生产,这个也是有问题的。
 *     应该是生产完后等消费者把它消费掉后,再继续生产。
 *
 * 正常的情况:
 *         生产者:
 *             先看是否有数据了,如果有,就等着消费者来消费。如果没有,就生产。生产完后通知消费者来消费包子。。。
 *         消费者:
 *             先看是否有数据,如果有,就消费。如果没有,就等待,通知生产者去生产。
 *
 * 为了解决这个问题,java就提供了一种机制:  等待唤醒机制。
 *
 *   等待唤醒机制:
 *       Object类中有3个方法:
 *           public final void wait()
            public final void notify()
            public final void notifyAll()
    为什么这几个方法不在Thread中?
        因为这个方法的调用是通过锁对象调用的,而我们同步代码块的锁对象可以是任意对象,
        所以,这些方法就定义再Object中。
 * */
public class Demo6 {
    public static void main(String[] args) {
        //创建资源对象
        BaoZi bz = new BaoZi();
        //创建生产者和消费者
        SetThread st = new SetThread(bz);
        GetThread gt = new GetThread(bz);
        
        //创建线程
        Thread t1 = new Thread(st,"成产者");
        Thread t2 = new Thread(gt,"消费者");
        
        t2.setPriority(10);
        
        //启动线程
        t2.start();
        t1.start();
    }
}

package com.momo.demo;

public class GetThread implements Runnable {
    private BaoZi bz;

    public GetThread(BaoZi bz) {
        this.bz = bz;
    }

    @Override
    public void run() {
        // BaoZi bz = new BaoZi();
        while (true) {
            synchronized (bz) {
                if(!bz.boo) {//false !false= true   !true = false  
                    try {
                        bz.wait();//t2就等待,会释放锁对象.将来醒来的时候,是从这里醒过来的。
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(Thread.currentThread().getName()+":"+bz.name + ":" + bz.price);
                // System.out.println(Thread.currentThread().getName()+"消费了这个包子");
            
                //修改标记,唤醒线程
                bz.boo = false;
                bz.notify();//唤醒t1
            }
        }
    }
}
package com.momo.demo;

public class SetThread implements Runnable {
    private BaoZi bz;
    private int i = 0;

    public SetThread(BaoZi bz) {
        this.bz = bz;
    }

    @Override
    public void run() {
        // BaoZi bz = new BaoZi();
        while (true) {
            synchronized (bz) {
                //判断有没有
                if(bz.boo) {//false   true   
                    try {
                        bz.wait();//t1等待,释放锁
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                if (i % 2 == 0) {
                    bz.name = "肉包子";
                    bz.price = 2;
                    
                     System.out.println(Thread.currentThread().getName()+"生产了一个肉包子");
                } else {
                    bz.name = "菜包子";
                    bz.price = 1;
                     System.out.println(Thread.currentThread().getName()+"生产了一个菜包子");
                }
                // System.out.println(Thread.currentThread().getName()+"生产了一个包子");
                i++;
                //修改标记,唤醒线程
                bz.boo = true;
                bz.notify();    //唤醒t2,唤醒后并不是马上就执行了,还是要抢cpu的执行权。
            }
        }
    }

}
package com.momo.demo;

public class BaoZi {
    String name;
    int price;
    boolean boo;//默认值是false,代表没有,如果是true了,就代表有了
}

原文地址:https://www.cnblogs.com/ironman-yan/p/11191630.html