线程(四)等待唤醒机制

等待唤醒机制

1 线程间通信

概念:多个线程在处理同⼀个资源,但是处理的动作(线程的任务)却不相同
⽐如:线程A⽤来⽣成包⼦的,线程B⽤来吃包⼦的,包⼦可以理解为同⼀资源,线程A与线程B
处理的动作,⼀个是⽣产,⼀个是消费,那么线程A与线程B之间就存在线程通信问题。
在这里插入图片描述
为什么要处理线程间的通信:
多个线程并发执⾏时, 在默认情况下CPU是随机切换线程的,当我们需要多个线程来共同完成⼀
件任务,并且我们希望他们有规律的执⾏,那么多线程之间需要⼀些协调通信,以此来帮我们达
到多线程共同操作⼀份数据。
如何保证线程通信有效资源利用率:
多个线程在处理同⼀个资源,并且任务不同时,需要线程通信来帮助解决线程之间对同⼀个变量
的使⽤或操作。就是多个线程在操作同⼀份数据时,避免对同⼀共享变量的争夺。也就是我们需
要通过⼀定的⼿段使各个线程能有效 的利⽤资源。⽽这种⼿段即 – 等待唤醒机制。

2 等待唤醒机制

等待唤醒机制
这是多个线程间的⼀种协作机制。
在一个线程进行规定操作后,就进入了等待状态(wait()),等待其他线程执行完他们的指定代码过后
后再将其唤醒( notify() );在有多个线程进⾏等待时,如果需要,可以使⽤ notifyAll() 来唤醒所有的等待线程
wait/notify 就是线程之间的一种协作机制。
等待唤醒中的⽅法
等待唤醒机制就是⽤于解决线程间通信的问题的,使⽤到的3个⽅法的含义如下:

  1. **wait:**线程不再活动,不再参与调度,进⼊ wait set 中,因此不会浪费 CPU 资源,也不会
    去竞争锁了,这时的线程状态即是 WAITING。它还要等着别的线程执⾏⼀个特别的动作,
    也即是“通知( notify )”在这个对象上等待的线程从 wait set 中释放出来,重新进⼊到调度队
    列( ready queue )中。
  2. **notify:**则选取所通知对象的 wait set 中的⼀个线程释放;例如,餐馆有空位置后,等候就
    餐最久的顾客最先⼊座。
  3. **notifyAll:**则释放所通知对象的 wait set 上的全部线程

调⽤wait和notify⽅法需要注意的细节
1.wait 方法与notify 方法 必须要由同一个锁对象调用。因为:对应的锁对象可以通过notify唤醒使用同一个锁对象调用wait方法后的进程。
2. wait⽅法与notify⽅法是属于Object类的⽅法的。因为:锁对象可以是任意对象,⽽任意对
象的所属类都是继承了Object类的。
3. wait⽅法与notify⽅法必须要在同步代码块或者是同步函数中使⽤。因为:必须要通过锁对
象调⽤这2个⽅法。

3 案例 双端通信:模拟图片加载与显示的过程

需求:

  1. 线程load:
    1.加载图片,模拟加载过程
    2.加载完成,设置图片状态 isLoad =true;
    3.唤醒show线程
    4.判断图片是否显示完成,如果没有完成,则等待
    5.被唤醒,继续下载图片,模拟下载完成
  2. 线程show:
    1.判断图片是否加载完成,若没有完成,则等待
    2.被唤醒,显示图片,模拟显示过程
    3.显示完成,设置图片状态 isShow=true;
    4.唤醒load线程
    实现:
    1.定义共享资源类 Picture
   // 线程的共享对象 Picture
   public class Picture {
    boolean isLoad; //判断是否加载完成
    boolean isShow; // 判断是否显示完成
}

2.LoadPicture 线程

public class LoadPicture extends Thread {
   // 定义共享资源picture
    private Picture picture;
    public LoadPicture(Picture picture) {
        this.picture = picture;
    }

    // 加载图片,模拟加载过程
    @Override
    public void run() {
        for (int i = 1; i <= 100; i++) {
            System.out.println("正在加载..." + i + "%");
        }
        try {
            Thread.sleep(50);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 2.加载完成,设置图片状态 isLoad =true;
        System.out.println("加载完成");
        picture.isLoad = true;
        //唤醒ShowLoad线程
        synchronized (picture) {
            picture.notify();
        }

        //判断图片是否显示完成,如果没有完成,则等待
        if (!picture.isShow) {
            System.out.println("等待图片显示");
            synchronized (picture) {
                try {
                    picture.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        //被唤醒,继续下载图片,模拟下载完成
        for (int i = 1; i <= 100; i++) {
            System.out.println("正在下载..." + i + "%");
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("下载完成");
    }
}

3.ShowPicture线程

public class ShowPicture extends Thread {
    private Picture picture;
    public ShowPicture(Picture picture) {
        this.picture = picture;
    }
    @Override
    public void run() {
        //如果isLoad是false 则线程等待
        if (!picture.isLoad) {
            System.out.println("等待加载完成");
            synchronized (picture) {
                try {
                    picture.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                try {
                    Thread.sleep(2000);
                    System.out.println("图片显示完成");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        //显示完成,设置图片状态 isShow=true;
        picture.isShow = true;
        //唤醒load线程 notify()
        synchronized (picture) {
            picture.notify();
        }
    }
}

4.测试类

public class TestDemo {
    public static void main(String[] args) {
        Picture picture = new Picture();
        // 两个线程共享同一个资源对象 picture
        Thread load = new LoadPicture(picture);
        Thread show = new ShowPicture(picture);
        load.start();
        show.start();
    }
}

4 生产者与消费者问题

生产者线程⽣产商品,消费者线程消费商品。
1.当商品没有时(商品池子为空 isEmpty 为true),消费者线程等待
2.生产者线程⽣产商品(商品池子不为空 isEmpty 为false),并通知消费者线程( 解除消费者的等待状态 )
3.有商品时,那么生产者线程进⼊等待状态。接下来,消费者线程能否进⼀步执⾏则取决于 锁的获取情况。
如果消费者获取到锁,那么就执⾏消费动作,商品买完( 商品池子为空 isEmpty 为true ),
并通知生产者线程( 解除生产者的等待状态 ),消费者线程进⼊等待。
生产者线程能否进⼀步执⾏则取决于锁的获取情况

定义 共享对象 Product

public class Product {
    //初始商品数 5 
    int count = 5; 
    // 此时商品池子为isEmpty=false
    boolean isEmpty=false;
}

定义消费者线程

public class Consumer extends Thread {
    Product product;
    public Consumer(Product product) {
        this.product = product;
    }
    @Override
    public void run() {
        while (true) {
               //  商品池子为空 则消费者等待 并通知生产者
            if (product.isEmpty == true) {
             System.out.println("消费者:厂家没货了");
                synchronized (product) {
                    try {
                        product.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
            //有货
            System.out.println("消费");
            product.count--;
            if (product.count == 0) 
             //商品个数为0 则商品池子isEmpty= true; 
                product.isEmpty= true;
                synchronized (product) {
                // 唤醒生产者线程
                    product.notify();
                }
            }
        }
    }
}

定义生产者线程:

public class Production extends Thread {
    Product product = new Product();
    public Production(Product product) {
        this.product = product;
    }
    @Override
    public void run() {
        while (true) {
            if (product.isEmpty == false) {
                synchronized (product) {
                    try {
                        product.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

            }
            // 没有产品 生产产品
            product.count += 2;
            if (product.count > 0) {
                System.out.println("生产者:产品已生产,快来购买");
                product.isEmpty = false;
                synchronized (product) {
                //唤醒消费者线程
                    product.notify();
                }

            }
        }
    }
}

测试类:

public class TestDemo {
    public static void main(String[] args) {
        Product product = new Product();
        Production production = new Production(product);
        Consumer consumer = new Consumer(product);
        production.start();
        consumer.start();
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值