多线程:线程间通信

为了保证线程间能够进行数据和逻辑的交互,就引入了一种【等待唤醒机制】

案例分析

详细过程:

需求分析:

代码实现

public class BaoZi {

    //包子皮
    String pi;
    //包子馅
    String xian;

    //包子有没有,初始状态为没有
    boolean flag = false;
}

public class BaoZiPu extends Thread{

    //把包子对象作为锁对象
    private BaoZi bz;

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

    @Override
    public void run() {
        int count = 0;//定义一个变量用来循环做不同的包子
        synchronized (bz){
            while(bz.flag){
                //有包子就进入WAITING状态
                try {
                    bz.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            //没有包子就开始做包子
            if(count%2 == 0){
                bz.pi = "薄皮";
                bz.xian = "三鲜馅";
            }else{
                bz.pi = "冰皮";
                bz.xian = "韭菜馅";
            }
            count++;
            System.out.println("包子铺正在生产"+bz.pi+bz.xian+"包子!");

            //做包子需要花3秒时间
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(bz.pi+bz.xian+"包子已经做好了,可以开吃了!");
            bz.flag = true;//修改包子状态为有
            bz.notify();//唤醒顾客
        }
    }
}

public class BaoZiEat extends Thread{

    private BaoZi bz;

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

    @Override
    public void run() {
        synchronized (bz){
            while(!bz.flag){
                try {
                    bz.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("吃货正在吃"+bz.pi+bz.xian+"包子");
            System.out.println(bz.pi+bz.xian+"包子吃完了!");
            bz.flag = false;
            bz.notify();
            System.out.println("=========================");
        }
    }
}

public class BaoZiDemo {
    public static void main(String[] args) {
        BaoZi bz = new BaoZi();
        new BaoZiPu(bz).start();
        new BaoZiEat(bz).start();

    }
}

这里有个问题一定要十分注意:为什么要在两个线程所在类的构造方法中都传递BaoZi变量?下面这两种做法是不对的:

  • 在两个线程中分别直接创建包子对象BaoZi bz = new BaoZi();在测试的时候分别new BaoZiPu(new BaoZi).start(),以及new BaoZiEat(new BaoZi).start()
  • 为什么是错的呢?notify只能唤醒“同对象wait”的线程,如果有两个BaoZi对象,那么锁对象不一样就无法唤醒了。

对于同一个资源,两个线程一个是醒的另一个就在等待,另一个醒了这一个又在等待……保证了有规律地运行。

如果要想让线程重复执行,可以将【包含synchronized在内的代码】包裹在死循环中。注意千万别把死循环写在了synchronized内部,否则将永远出不了这个线程了。

发布了70 篇原创文章 · 获赞 1 · 访问量 2276

猜你喜欢

转载自blog.csdn.net/caozp913/article/details/103450546