终于明白阿里百度为什么拿WaitNotify通知机制考察求职者了

本文主要是介绍终于明白阿里百度为什么拿WaitNotify通知机制考察求职者了,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

作为一名java程序员,相信都知道wait/notify的通知机制可以用来实现线程间通信。

求职面试时,不少公司都会出类似这样的题目。笔者有次面试时,面试官就问了这样一个问题:

wait/notify/notifyAll一般适用于什么场景?

由于笔者之前对这个知识点没有重视,面试官调侃说,你对WaitNotify通知机制都没有掌握,难怪你期望薪资那么低。

我们知道,wait表示线程的等待,调用该方法会导致线程阻塞,直至另一线程调用notify或notifyAll方法才可另其继续执行。经典的生产者、消费者模式即是使用wait/notify机制得以完成。

在了解wait/notify通知机制前,我们先回顾下java线程的生命周期。

今天我们针对此知识点,来编写个例子加深理解。

假设我开了一家水果实体店,日常经营主要有两项,一项是进货,一项是卖货。需要满足如下条件:

  1. 往店里进货,前提是店里库存不足,如果库存充足,则无需进货,直到把货卖出去了。

  2. 卖货,前提店里库存充足,库存不足时就要进货。

新建个水果店抽象类AbstractFruitStore

1public interface AbstractFruitStore {
2  void consumer(int num);
3
4  void producer(int num);
5}

水果实体店类实现AbstractFruitStore

 1/**2 * 水果店3 */4public class FruitStore implements AbstractFruitStore {5 private final int MAX_SIZE = 100;6 private LinkedList list = new LinkedList();78 @Override9 public void consumer(int num) {
10    synchronized (list) {
11        //条件不满足,进入等待状态
12        while (num > list.size()) {
13            System.out.println("【要消费】:" + num + "\t【现库存量】:" + list.size() + "\t库存不足,暂不支持消费");
14            try {
15                //条件不满足,生产阻塞
16                list.wait();
17            } catch (InterruptedException e) {
18                e.printStackTrace();
19            }
20        }
21        //条件满足,开始消费
22        for (int i = 0; i < num; i++) {
23            list.remove();
24        }
25        System.out.println("【已消费】:" + num + "\t【现库存量】:" + list.size());
26        list.notifyAll();
27    }
28}
29
30@Override
31public void producer(int num) {
32    synchronized (list) {
33        while (list.size() + num > MAX_SIZE) {
34            System.out.println("【要生产】:" + num + "\t【库存已有】:" + list.size() + "\t库存充足,暂不支持生产");
35            try {
36                //条件不满足,生产阻塞
37                list.wait();
38            } catch (InterruptedException e) {
39                e.printStackTrace();
40            }
41        }
42        for (int i = 0; i < num; i++) {
43            list.add(new Object());
44        }
45        System.out.println("【已生产】:" + num + "\t【现库存量】:" + list.size());
46        list.notifyAll();
47    }
48  }
49}

生产者Producer

 1 /**2  * 生产者3  */4public class Producer extends Thread {5   private int num;6   public AbstractFruitStore abstractFruitStore;78   public Producer(AbstractFruitStore abstractFruitStore) {9    this.abstractFruitStore = abstractFruitStore;
10   }
11
12   public void setNum(int num) {
13    this.num = num;
14   }
15
16   @Override
17   public void run() {
18    producer(num);
19   }
20
21   public void producer(int num) {
22    abstractFruitStore.producer(num);
23  }
24}

消费者Consumer

 1/**2 * 消费者3 */4public class Consumer extends Thread {56    private int num;78    private AbstractFruitStore abstractFruitStore;9
10    public Consumer(AbstractFruitStore abstractFruitStore) {
11    this.abstractFruitStore = abstractFruitStore;
12    }
13
14    public void run() {
15     consumer(num);
16    }
17
18    public void consumer(int num) {
19     abstractFruitStore.consumer(num);
20    }
21
22    public void setNum(int num) {
23     this.num = num;
24   }
25}
 1public class WaitNotifyTest {2 public static void main(String[] args) {3    AbstractFruitStore abstractFruitStore = new FruitStore();4    //消费者对象5    Consumer c1 = new Consumer(abstractFruitStore);6    Consumer c2 = new Consumer(abstractFruitStore);7    Consumer c3 = new Consumer(abstractFruitStore);89    c1.setNum(10);
10    c2.setNum(20);
11    c3.setNum(30);
12
13    // 生产者对象
14    Producer p1 = new Producer(abstractFruitStore);
15    Producer p2 = new Producer(abstractFruitStore);
16    Producer p3 = new Producer(abstractFruitStore);
17    Producer p4 = new Producer(abstractFruitStore);
18
19    p1.setNum(20);
20    p2.setNum(30);
21    p3.setNum(50);
22    p4.setNum(80);
23
24    //启动消费者线程
25    c1.start();
26    c2.start();
27    c3.start();
28    //启动生产者线程
29    p1.start();
30    p2.start();
31    p3.start();
32    p4.start();
33  }
34}

运行结果:

从中我们可以得出,Wait-Notify场景一般和下面3个因素相关:

  1. 状态变量(State Variable)
    当线程需要wait时,是因为一些条件得不到满足导致的。例如往队列里填充数据,当队列元素已经满时,线程就需要wait停止运行。当队列元素有空缺时,再继续自己的执行。

  2. 条件断言(Condition Predicate)


    当线程确定是否进入wait或者是从notify醒来的时候是否继续往下执行,大部分都要测试状态条件是否满足。

  3. 条件队列(Condition Queue)
    每个对象都有一个内置的条件队列,当一个线程在该对象锁上调用wait函数的时候,就会将该线程加入到该对象的条件队列中。

总结

如果线程调用了Object对象的wait()方法,那么线程会处于该对象的等待池中,等待池中的线程不会去竞争该对象的锁。

当有线程调用了Object对象的notify()方法(只随机唤醒一个wait线程)或是notifyAll()方法(唤醒所有wait线程)被唤醒的的线程会进入该对象的锁池中,锁池中的线程会去竞争该对象锁。

优先级高的线程竞争到对象锁的概率大,假若某线程没有竞争到该对象锁,它还会留在锁池中,只有线程再次调用wait()方法,它才会重新回到等待池中。而竞争到对象锁的线程则继续往下执行,直到执行完了synchronized代码块,它会释放掉该对象锁,这时锁池中的线程会继续竞争该对象锁。

一个知识点不仅能考验求职者的对该知识点的掌握程度,还延伸出其他知识点,考验求职者的知识面,难怪阿里百度这样的大公司喜欢在面试时拿它来考验求职者。

由于笔者水平有限,文中纰漏之处在所难免,权当抛砖引玉,不妥之处,请大家批评指正。

 

-END-

作者:洪生鹏  擅长java、Android、qt、小程序平台开发。技术交流、媒体合作、品牌宣传请添加微信: hsp-88ios

猜你喜欢

养成了定期更新简历的习惯,我不再像以前那么焦虑了

更多惊喜,请长按二维码识别关注

你若喜欢,别忘了帮忙点【在看

这篇关于终于明白阿里百度为什么拿WaitNotify通知机制考察求职者了的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/227624

相关文章

springboot整合阿里云百炼DeepSeek实现sse流式打印的操作方法

《springboot整合阿里云百炼DeepSeek实现sse流式打印的操作方法》:本文主要介绍springboot整合阿里云百炼DeepSeek实现sse流式打印,本文给大家介绍的非常详细,对大... 目录1.开通阿里云百炼,获取到key2.新建SpringBoot项目3.工具类4.启动类5.测试类6.测

SpringRetry重试机制之@Retryable注解与重试策略详解

《SpringRetry重试机制之@Retryable注解与重试策略详解》本文将详细介绍SpringRetry的重试机制,特别是@Retryable注解的使用及各种重试策略的配置,帮助开发者构建更加健... 目录引言一、SpringRetry基础知识二、启用SpringRetry三、@Retryable注解

SpringKafka错误处理(重试机制与死信队列)

《SpringKafka错误处理(重试机制与死信队列)》SpringKafka提供了全面的错误处理机制,通过灵活的重试策略和死信队列处理,下面就来介绍一下,具有一定的参考价值,感兴趣的可以了解一下... 目录引言一、Spring Kafka错误处理基础二、配置重试机制三、死信队列实现四、特定异常的处理策略五

java中反射(Reflection)机制举例详解

《java中反射(Reflection)机制举例详解》Java中的反射机制是指Java程序在运行期间可以获取到一个对象的全部信息,:本文主要介绍java中反射(Reflection)机制的相关资料... 目录一、什么是反射?二、反射的用途三、获取Class对象四、Class类型的对象使用场景1五、Class

Nginx之upstream被动式重试机制的实现

《Nginx之upstream被动式重试机制的实现》本文主要介绍了Nginx之upstream被动式重试机制的实现,可以通过proxy_next_upstream来自定义配置,具有一定的参考价值,感兴... 目录默认错误选择定义错误指令配置proxy_next_upstreamproxy_next_upst

Android 悬浮窗开发示例((动态权限请求 | 前台服务和通知 | 悬浮窗创建 )

《Android悬浮窗开发示例((动态权限请求|前台服务和通知|悬浮窗创建)》本文介绍了Android悬浮窗的实现效果,包括动态权限请求、前台服务和通知的使用,悬浮窗权限需要动态申请并引导... 目录一、悬浮窗 动态权限请求1、动态请求权限2、悬浮窗权限说明3、检查动态权限4、申请动态权限5、权限设置完毕后

Spring排序机制之接口与注解的使用方法

《Spring排序机制之接口与注解的使用方法》本文介绍了Spring中多种排序机制,包括Ordered接口、PriorityOrdered接口、@Order注解和@Priority注解,提供了详细示例... 目录一、Spring 排序的需求场景二、Spring 中的排序机制1、Ordered 接口2、Pri

MySQL 缓存机制与架构解析(最新推荐)

《MySQL缓存机制与架构解析(最新推荐)》本文详细介绍了MySQL的缓存机制和整体架构,包括一级缓存(InnoDBBufferPool)和二级缓存(QueryCache),文章还探讨了SQL... 目录一、mysql缓存机制概述二、MySQL整体架构三、SQL查询执行全流程四、MySQL 8.0为何移除查

一文详解Java Condition的await和signal等待通知机制

《一文详解JavaCondition的await和signal等待通知机制》这篇文章主要为大家详细介绍了JavaCondition的await和signal等待通知机制的相关知识,文中的示例代码讲... 目录1. Condition的核心方法2. 使用场景与优势3. 使用流程与规范基本模板生产者-消费者示例

一文带你理解Python中import机制与importlib的妙用

《一文带你理解Python中import机制与importlib的妙用》在Python编程的世界里,import语句是开发者最常用的工具之一,它就像一把钥匙,打开了通往各种功能和库的大门,下面就跟随小... 目录一、python import机制概述1.1 import语句的基本用法1.2 模块缓存机制1.