【大数据】学习笔记 1 Java SE 第9章 多线程 9.5 等待唤醒机制

【大数据】学习笔记

在这里插入图片描述

1 Java SE

第9章 多线程

9.5 等待唤醒机制
9.5.1 线程间通信

为什么要处理线程间通信:

多个线程在处理同一个资源,但是处理的动作(线程的任务)却不相同。而多个线程并发执行时, 在默认情况下CPU是随机切换线程的,当我们需要多个线程来共同完成一件任务,并且我们希望他们有规律的执行, 那么多线程之间需要一些通信机制,可以协调它们的工作,以此来帮我们达到多线程共同操作一份数据。

比如:线程A用来生成包子的,线程B用来吃包子的,包子可以理解为同一资源,线程A与线程B处理的动作,一个是生产,一个是消费,此时B线程必须等到A线程完成后才能执行,那么线程A与线程B之间就需要线程通信,即—— 等待唤醒机制。

9.5.2 等待唤醒机制

什么是等待唤醒机制

这是多个线程间的一种协作机制。谈到线程我们经常想到的是线程间的竞争(race),比如去争夺锁,但这并不是故事的全部,线程间也会有协作机制。

就是在一个线程满足某个条件时,就进入等待状态(wait()/wait(time)), 等待其他线程执行完他们的指定代码过后再将其唤醒(notify());或可以指定wait的时间,等时间到了自动唤醒;在有多个线程进行等待时,如果需要,可以使用 notifyAll()来唤醒所有的等待线程。wait/notify 就是线程间的一种协作机制。

  1. wait:线程不再活动,不再参与调度,进入 wait set 中,因此不会浪费 CPU 资源,也不会去竞争锁了,这时的线程状态即是 WAITING或TIMED_WAITING。它还要等着别的线程执行一个特别的动作,也即是“通知(notify)”或者等待时间到,在这个对象上等待的线程从wait set 中释放出来,重新进入到调度队列(ready queue)中
  2. notify:则选取所通知对象的 wait set 中的一个线程释放;
  3. notifyAll:则释放所通知对象的 wait set 上的全部线程。

注意:

被通知线程被唤醒后也不一定能立即恢复执行,因为它当初中断的地方是在同步块内,而此刻它已经不持有锁,所以她需要再次尝试去获取锁(很可能面临其它线程的竞争),成功后才能在当初调用 wait 方法之后的地方恢复执行。

总结如下:

  • 如果能获取锁,线程就从 WAITING 状态变成 RUNNABLE(可运行) 状态;
  • 否则,线程就从 WAITING 状态又变成 BLOCKED(等待锁) 状态

调用wait和notify方法需要注意的细节

  1. wait方法与notify方法必须要由同一个锁对象调用。因为:对应的锁对象可以通过notify唤醒使用同一个锁对象调用的wait方法后的线程。
  2. wait方法与notify方法是属于Object类的方法的。因为:锁对象可以是任意对象,而任意对象的所属类都是继承了Object类的。
  3. wait方法与notify方法必须要在同步代码块或者是同步函数中使用。因为:必须要通过锁对象调用这2个方法。
9.5.3 生产者与消费者问题

等待唤醒机制可以解决经典的“生产者与消费者”的问题。

生产者与消费者问题(英语:Producer-consumer problem),也称有限缓冲问题(英语:Bounded-buffer problem),是一个多线程同步问题的经典案例。该问题描述了两个(多个)共享固定大小缓冲区的线程——即所谓的“生产者”和“消费者”——在实际运行时会发生的问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。

生产者与消费者问题中其实隐含了两个问题:

  • 线程安全问题:因为生产者与消费者共享数据缓冲区,不过这个问题可以使用同步解决。
  • 线程的协调工作问题:
    • 要解决该问题,就必须让生产者线程在缓冲区满时等待(wait),暂停进入阻塞状态,等到下次消费者消耗了缓冲区中的数据的时候,通知(notify)正在等待的线程恢复到就绪状态,重新开始往缓冲区添加数据。同样,也可以让消费者线程在缓冲区空时进入等待(wait),暂停进入阻塞状态,等到生产者往缓冲区添加数据之后,再通知(notify)正在等待的线程恢复到就绪状态。通过这样的通信机制来解决此类问题。

【1】一个厨师一个服务员问题

案例:有家餐馆的取餐口比较小,只能放10份快餐,厨师做完快餐放在取餐口的工作台上,服务员从这个工作台取出快餐给顾客。现在有1个厨师和1个服务员。

package com.dingjiaxiong.thread5;

/**
 * @Projectname: BigDataStudy
 * @Classname: TestCommunicate
 * @Author: Ding Jiaxiong
 * @Date:2023/4/27 16:12
 */

public class TestCommunicate {
    
    
    public static void main(String[] args) {
    
    
        // 1、创建资源类对象
        Workbench workbench = new Workbench();

        // 2、创建和启动厨师线程
        new Thread("厨师") {
    
    
            public void run() {
    
    
                while (true) {
    
    
                    workbench.put();
                }
            }
        }.start();

        // 3、创建和启动服务员线程
        new Thread("服务员") {
    
    
            public void run() {
    
    

                while (true) {
    
    
                    workbench.take();
                }
            }
        }.start();
    }

}

// 1、定义资源类
class Workbench {
    
    
    private static final int MAX_VALUE = 10;
    private int num;

    public synchronized void put() {
    
    
        if (num >= MAX_VALUE) {
    
    
            try {
    
    
                this.wait();
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
        }
        num++;
        System.out.println(Thread.currentThread().getName() + "制作了一份快餐,现在工作台上有:" + num + "份快餐");
        this.notify();
    }

    public synchronized void take() {
    
    
        if (num <= 0) {
    
    
            try {
    
    
                this.wait();
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
        }
        num--;
        System.out.println(Thread.currentThread().getName() + "取走了一份快餐,现在工作台上有:" + num + "份快餐");
        this.notify();
    }
}

在这里插入图片描述

【2】多个厨师多个服务员问题

案例:有家餐馆的取餐口比较小,只能放10份快餐,厨师做完快餐放在取餐口的工作台上,服务员从这个工作台取出快餐给顾客。现在有多个厨师和多个服务员。

package com.dingjiaxiong.thread5;

/**
 * @Projectname: BigDataStudy
 * @Classname: TestCommunicate2
 * @Author: Ding Jiaxiong
 * @Date:2023/4/27 16:13
 */

public class TestCommunicate2 {
    
    
    public static void main(String[] args) {
    
    
        // 1、创建资源类对象
        WindowBoard windowBoard = new WindowBoard();

        // 2、创建和启动厨师线程
        // 3、创建和启动服务员线程
        Cook c1 = new Cook("张三", windowBoard);
        Cook c2 = new Cook("李四", windowBoard);
        Waiter w1 = new Waiter("小红", windowBoard);
        Waiter w2 = new Waiter("小绿", windowBoard);

        c1.start();
        c2.start();
        w1.start();
        w2.start();
    }

}

//1、定义资源类
class WindowBoard {
    
    
    private static final int MAX_VALUE = 10;
    private int num;

    public synchronized void put() {
    
    
        while (num >= MAX_VALUE) {
    
    
            try {
    
    
                this.wait();
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
        }
        num++;
        System.out.println(Thread.currentThread().getName() + "制作了一份快餐,现在工作台上有:" + num + "份快餐");
        this.notifyAll();
    }

    public synchronized void take() {
    
    
        while (num <= 0) {
    
    
            try {
    
    
                this.wait();
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
        }
        num--;
        System.out.println(Thread.currentThread().getName() + "取走了一份快餐,现在工作台上有:" + num + "份快餐");
        this.notifyAll();
    }
}


//2、定义厨师类
class Cook extends Thread {
    
    
    private WindowBoard windowBoard;

    public Cook(String name, WindowBoard windowBoard) {
    
    
        super(name);
        this.windowBoard = windowBoard;
    }

    public void run() {
    
    
        while (true) {
    
    
            windowBoard.put();
        }
    }
}


//3、定义服务员类
class Waiter extends Thread {
    
    
    private WindowBoard windowBoard;

    public Waiter(String name, WindowBoard windowBoard) {
    
    
        super(name);
        this.windowBoard = windowBoard;
    }

    public void run() {
    
    
        while (true) {
    
    
            windowBoard.take();
        }
    }
}

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_44226181/article/details/130480169
今日推荐