美团Java开发一面凉经

news2024/12/24 2:31:41

目录

    • 1.HashMap底层数据结构
    • 2.列举几个常见的线程安全容器
    • 3.HashMap线程问题
    • 4.concurrentHashMap
    • 5.ConcurrentModificationException
    • 6.Spring AOP、IOC、DI介绍下
    • 7.不使用依赖注入,使用传统方式的声明会有什么问题
    • 8.最左前缀原则
    • 9.TCP三次握手、四次挥手

1.HashMap底层数据结构

在 JDK 1.7 中,HashMap 使用的是数组 + 链表实现。
在 JDK 1.8 中使用的是数组 + 链表或红黑树实现的。

put实现原理
(1)先判断当前Node[]数组是不是为空,为空就新建,不为空就对hash值与容量-1做与运算得到数组下标
(2)然后会判断当前数组位置有没有元素,没有的话就把值插到当前位置,有的话就说明遇到了哈希碰撞
(3)遇到哈希碰撞后,如果Hash值相同且equals内容也相同,直接覆盖,就会看下当前链表是不是以红黑树的方式存储,是的话,就会遍历红黑树,看有没有相同key的元素,有就覆盖,没有就执行红黑树插入
(4)如果是普通链表,则按普通链表的方式遍历链表的元素,判断p.next = null的情况下,直接存放追加在next后面,然后我们要检查一下如果链表长度大于8且数组容量>=64链表转换成红黑树,否则查找到链表中是否存在该key,如果存在直接修改value值,如果没有继续遍历
(5)如果++size > threshold(阈值)就扩容

HashMap中put的实现原理
HashMap何时会链表转红黑树

2.列举几个常见的线程安全容器

1.Vector
2.HashTable
3.ConcurrentHashMap:分段
4.CopyOnWriteArrayList:写时复制
5.CopyOnWriteArraySet:写时复制

3.HashMap线程问题

JDK1.8 中,由于多线程对HashMap进行put操作,调用了HashMap#putVal(),具体原因:假设两个线程A、B都在进行put操作,并且hash函数计算出的插入下标是相同的,当线程A执行完第六行代码后由于时间片耗尽导致被挂起,而线程B得到时间片后在该下标处插入了元素,完成了正常的插入,然后线程A获得时间片,由于之前已经进行了hash碰撞的判断,所有此时不会再进行判断,而是直接进行插入,这就导致了线程B插入的数据被线程A覆盖了,从而线程不安全。

4.concurrentHashMap

ConcurrentHashMap
JDK1.7ConcurrentHashMap底层实现原理:
数据结构:Segment(大数组) + HashEntry(小数组) + 链表,每个 Segment 对应一把锁,如果多个线程访问不同的 Segment,则不会冲突
JDK1.8ConcurrentHashMap底层实现原理:
数据结构:Node 数组 + 链表或红黑树,数组的每个头节点作为锁,如果多个线程访问的头节点不同,则不会冲突。首次生成头节点时如果发生竞争,利用 cas 而非 syncronized,进一步提升性能

ConcurrentHashMap的整体架构
数据结构:Node 数组 + 链表或红黑树,数组的每个头节点作为锁,如果多个线程访问的头节点不同,则不会冲突。首次生成头节点时如果发生竞争,利用 cas 而非 syncronized,进一步提升性能

在这里插入图片描述
这个是ConcurrentHashMap在JDK1.8中的存储结构,它是由数组、单向链表、红黑树组成。
当我们初始化一个ConcurrentHashMap实例时,默认会初始化一个长度为16的数组。由于ConcurrentHashMap它的核心仍然是hash表,所以必然会存在hash冲突问题。
ConcurrentHashMap采用链式寻址法来解决hash冲突。
当hash冲突比较多的时候,会造成链表长度较长,这种情况会使得ConcurrentHashMap中数据元素的查询复杂度变成O(n)。因此在JDK1.8中,引入了红黑树的机制。
当数组长度大于64并且链表长度大于等于8的时候,单项链表就会转换为红黑树。
另外,随着ConcurrentHashMap的动态扩容,一旦链表长度小于8,红黑树会退化成单向链表。

ConcurrentHashMap的基本功能

ConcurrentHashMap本质上是一个HashMap,因此功能和HashMap一样,但是ConcurrentHashMap在HashMap的基础上,提供了并发安全的实现。
并发安全的主要实现是通过对指定的Node节点加锁,来保证数据更新的安全性。
在这里插入图片描述
ConcurrentHashMap在性能方面做的优化

  • 在JDK1.8中,ConcurrentHashMap锁的粒度是数组中的某一个节点,而在JDK1.7,锁定的是Segment,锁的范围要更大,因此性能上会更低。
  • 引入红黑树,降低了数据查询的时间复杂度,红黑树的时间复杂度是O(logn)。
  • 当数组长度不够时,ConcurrentHashMap需要对数组进行扩容,在扩容的实现上,ConcurrentHashMap引入了多线程并发扩容的机制,简单来说就是多个线程对原始数组进行分片后,每个线程负责一个分片的数据迁移,从而提升了扩容过程中数据迁移的效率。
    在这里插入图片描述
  • ConcurrentHashMap中有一个size()方法来获取总的元素个数,而在多线程并发场景中,在保证原子性的前提下来实现元素个数的累加,性能是非常低的。ConcurrentHashMap在这个方面的优化主要体现在两个点:
  • 当线程竞争不激烈时,直接采用CAS来实现元素个数的原子递增。
    如果线程竞争激烈,使用一个数组来维护元素个数,如果要增加总的元素个数,则直接从数组中随机选择一个,再通过CAS实现原子递增。它的核心思想是引入了数组来实现对并发更新的负载。

在这里插入图片描述
为什么不用ReentrantLock而用synchronized ?
减少内存开销:如果使用ReentrantLock则需要节点继承AQS来获得同步支持,增加内存开销,而1.8中只有头节点需要进行同步。
内部优化:synchronized则是JVM直接支持的,JVM能够在运行时作出相应的优化措施:锁粗化、锁消除、锁自旋等等。

5.ConcurrentModificationException

ConcurrentModificationException异常
当方法检测到对象的并发修改,但不允许这种修改时,抛出此异常。
modCount的作用
modCount就是修改次数,在具体的实现类中的Iterator中才会使用。在List集合中,ArrayList是List接口的实现类,
modCount:表示list集合结构上被修改的次数。(在ArrayList所有涉及结构变化的方法中,都增加了modCount的值)
list结构上别修改是指:改变了list的长度的大小或者是遍历结果中产生了不正确的结果的方式。add()和remove()方法会是modCount进行+1操作。modCount被修改后会产生ConcurrentModificationException异常, 这是jdk的快速失败原则。

下面进行试验

    public static void main(String[] args) {
        ArrayList<String> list=new ArrayList<String>();
        list.add("1");
        list.add("2");
        list.add("3");

        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()){
            String ele=iterator.next();
            if(ele.equals("2")) //(1)处
                list.remove(ele); //(2)处
        }
        System.out.println(list);
    }

看下ArrayList类的Iterator是如何实现的呢?
在这里插入图片描述
可以看出,调用next()方法获取下一个元素时,第一行代码就是调用了checkForComodification();,而该方法的核心逻辑就是比较modCount和expectedModCount这2个变量的值。
在上面的例子中,刚开始modCount和expectedModCount的值都为3,所以第1次获取元素"1"是没问题的,但是当执行完下面这行代码时:

list.remove(ele);

modCount的值就被修改成了4。(remove方法里面调用了fastRemove)
在这里插入图片描述
所以在第2次获取元素时,modCount和expectedModCount的值就不相等了,所以抛出了java.util.ConcurrentModificationException异常。
在这里插入图片描述
解决方案
使用Iterator的remove()方法
在这里插入图片描述

可以看出,每次删除一个元素,都会将modCount的值重新赋值给expectedModCount,这样2个变量就相等了,不会触发java.util.ConcurrentModificationException异常。

6.Spring AOP、IOC、DI介绍下

IOC
IOC—Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想。在Java开发中,IOC意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。

  • 谁控制谁,控制什么?
    传统Java SE程序设计,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;而IOC是有专门一个容器来创建这些对象,即由IOC容器来控制对 象的创建;谁控制谁?当然是IOC 容器控制了对象;控制什么?那就是主要控制了外部资源获取(不只是对象包括比如文件等)。
  • 为何是反转,哪些方面反转了?
    有反转就有正转,传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙创建及注入依赖对象;为何是反转?因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;哪些方面反转了?依赖对象的获取被反转了。

IOC的好处?
ioc的思想最核心的地方在于,资源不由使用资源者管理,而由不使用资源的第三方管理,这可以带来很多好处。第一,资源集中管理,实现资源的可配置和易管理。第二,降低了使用资源双方的依赖程度,也就是我们说的耦合度。也就是说,甲方要达成某种目的不需要直接依赖乙方,它只需要达到的目的告诉第三方机构就可以了,比如甲方需要一双袜子,而乙方它卖一双袜子,它要把袜子卖出去,并不需要自己去直接找到一个卖家来完成袜子的卖出。它也只需要找第三方,告诉别人我要卖一双袜子。这下好了,甲乙双方进行交易活动,都不需要自己直接去找卖家,相当于程序内部开放接口,卖家由第三方作为参数传入。甲乙互相不依赖,而且只有在进行交易活动的时候,甲才和乙产生联系。反之亦然。这样做什么好处么呢,甲乙可以在对方不真实存在的情况下独立存在,而且保证不交易时候无联系,想交易的时候可以很容易的产生联系。甲乙交易活动不需要双方见面,避免了双方的互不信任造成交易失败的问题。因为交易由第三方来负责联系,而且甲乙都认为第三方可靠。那么交易就能很可靠很灵活的产生和进行了。
这就是ioc的核心思想。生活中这种例子比比皆是,支付宝在整个淘宝体系里就是庞大的ioc容器,交易双方之外的第三方,提供可靠性可依赖可灵活变更交易方的资源管理中心。另外人事代理也是,雇佣机构和个人之外的第三方。

DI
依赖注入是指将依赖的对象实例交给spring帮我们注入 管理,从而释放对对象的管理权,比如可以统一替换接口的实现,更高效的开发程序

  1. set方法注入
  2. 构造方法注入
  3. @autowire 自动注入

AOP
面向切面编程,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取公共模块复用,降低耦合。

你们项目中有没有使用到AOP
记录操作日志,缓存,spring实现的事务
核心是:使用aop中的环绕通知+切点表达式(找到要记录日志的方法),通过环绕通知的参数获取请求方法的参数(类、方法、注解、请求方式等),获取到这些参数以后,保存到数据库

7.不使用依赖注入,使用传统方式的声明会有什么问题

主要是实现类之间的解耦,假如A类依赖B类,在实例化A类的话也要new一个B类,如果A的依赖的类换成C的话,所有实例化A的代码的new B都要替换掉,不利于代码维护。

8.最左前缀原则

过滤条件要使用索引必须按照索引建立时的顺序,依次满足,一旦跳过某个字段,索引后面的字段都无法被使用。

9.TCP三次握手、四次挥手

TCP协议
保证传输过程的三个关键的步骤,分别为三次握手、传输确认、四次挥手。
三次握手
在这里插入图片描述
三次握手是建立连接的过程,当客户端向服务端发起连接时,会先发一包连接请求数据,过去询问一下,能否与你建立连接,这包数据我们称之为SYN包。如果对端同意连接,则回复一包SYN+ACK包,客户端收到之后回复一包ACK包连接建立。
因为这个过程中互相发送了三包数据,所以称之为三次握手。
Q:为什么要三次握手,而不是两次握手,服务端回复完SYN+ACK包之后就建立连接
A:这是为了防止因为已失效的请求报文突然又传到服务器引起错误。解决网络信道不可靠的问题
如果没有第三次握手告诉服务器端客户端收的到服务器端传输的数据的话,服务器端是不知道客户端有没有接收到服务器端返回的信息的。服务端就认为这个连接是可用的,端口就一直开着,等到客户端因超时重新发出请求时,服务器就会重新开启一个端口连接。
这样一来,就会有很多无效的连接端口白白地开着,导致资源的浪费。
在这里插入图片描述
还有一种情况是已经失效的客户端发出的请求信息,由于某种原因传输到了服务器端,服务器端以为是客户端发出的有效请求,接收后产生错误。
在这里插入图片描述
Q:为什么不是四次握手?
A:因为通信不可能100%可靠,而上面的三次握手已经做好了通信的准备工作,再四次握手,并不能显著提高可靠性,而且也没有必要。
数据传输
在这里插入图片描述
经过三次握手之后,客户端和服务端都进入了数据传输状态。tcp协议需要在不可靠的信道上保证可靠的连接。现在就有几个问题需要面对:1. 一包数据有可能被拆成多包发送,如何处理丢包问题 ;2. 这些数据包到达的先后顺序不同,如何处理乱乱序问题。

针对以上的要求,TCP协议为每一个连接建立了一个发送缓冲区,从建立链接后的第一个字节的序列号为0,后面每个字节的序列号就会增加1。发送数据时,从发送缓冲区,取一部分数据组成发送报文,在其tcp协议头中会附带序列号和长度,接受端在收到数据后,需要回复确认报文。确认报文中的ACK,等于接收序列号加长度,也就是下一包数据需要发送的起始序列号。

这样一问一答的发送方式,能够使发送端确认发送的数据已经被对方收到,发送端也可以一次发送连续多包数据,接收端只需要回复一次ACK就可以了,这样发送端可以把待发送的数据分割成一系列的碎片,发送到对端。对端根据序列号和长度,在接受后重构出来完整的数据,假设其中丢失了某些数据包,在接收端可以要求发送端重传。比如丢失了100-199,这100个字节,接收端向发送端发送ACK = 100 报文,发送端收到后重传这一包数据,接受端进行补齐。

以上过程不区分客户端和服务端,TCP连接是全双工的,对于两端来说均采用上述机制。

四次挥手
处于连接状态的客户端和服务端都可以发起关闭连接请求,此时需要四次挥手来进行连接关闭。

1.假设客户端主动发起连接关闭请求,他需要将服务端发起一包FIN包,表示要关闭连接,自己进入终止等待1状态,这是第一次挥手。

2.服务端收到FIN包,发送一包ACK包,表示自己进入了关闭等待状态,客户端进入终止等待2状态,这是第二次挥手。

3.服务端此时还可以发送未发送的数据,而客户端还可以接收数据,待服务端发送完数据之后,发送一包FIN包,进入最后确认状态,这是第三次挥手。

4.客户端收到之后回复ACK包,进入超时等待状态,经过超时时间后关闭连接,而服务端收到ACK包后,立即关闭连接,这是第四次挥手。

Q:为什么客户端需要等待超时时间?
A:为了保证对方已收到ACK包,因为假设客户端发送完最后一包ACK包后就释放了连接,一旦ACK包在网络中丢失,服务端将一直停留在最后确认状态;如果客户端发送最后一包ACK包后,等待一段时间,这是服务端会因为没有收到ACK包会重发FIN包,客户端会响应这个FIN包重发ACK包并刷新超时时间。这个机制跟三次握手一样,也是为了保证在不可靠的网络链路中进行可靠的连接断开确认。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/535448.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

EasyExcel读取EXcel文件内容

目录 一 官方文档介绍 二 读取文件内容 1.根据文档内容建立读对象 2.创建读监听器 3.测试类代码 一 官方文档介绍 Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存&#xff0c;poi有一套SAX模式的API可以一定程度的解决…

(二十三)数据结构-哈希表

1 哈希表的基本介绍 1.1 用于存储的数据结构 在计算机中&#xff0c;数组和链表都可以用于数据的存储&#xff0c;既然有数据存储&#xff0c;那么必然要有数据的查询&#xff0c;因此我们在将数据存储进数组和链表中之后&#xff0c;必然要对它们进行查询操作。一个链表的查…

java+springboot+jsp农产品商城农场信息化系统多用户

系统功能包括前台&#xff1a;首页、商品信息、新闻资讯、我的、跳转到后台、购物车&#xff0c;管理员&#xff1a;个人中心、用户管理、员工管理、技术专家管理、部门信息管理、资金统计管理、农资信息管理、商品分类管理、商品信息管理、入库记录管理、出库记录管理、销售统…

如何调用api接口获取其中的数据

part1.API接口可以运用到的场景&#xff0c;主要包括以下几个方面&#xff1a; 1. 应用程序集成&#xff1a;API可以使不同的应用程序相互之间进行集成&#xff0c;比如将某个应用程序的数据传递给另一个应用程序&#xff0c;或者调用另一个应用程序的功能。 2. 数据共享&#…

cocos2dx游戏项目,集成到其他安卓项目工程之中!

背景 公司&#xff0c;想优化掉&#xff0c;在app中&#xff0c;以webview方式&#xff0c;加载游戏的方式。以安卓项目为例&#xff0c;改成&#xff1a;游戏项目导出安卓工程&#xff0c;可直接使用的aar资源。 第一步&#xff1a;cocos项目&#xff0c;构建安卓工程 安装…

icmp协议

1、icmp协议 2、工具之ping -c (设置ping的次数&#xff0c;默认无限次&#xff0c;可选) -i (设置ping的时间间隔&#xff0c;默认1秒&#xff0c;可选) -W (设置ping的超时时间&#xff0c;单位秒&#xff0c;可选) ping -c 3 -i 0.1 -W 0.1 www.baidu.com-i 自定义时间间…

接口自动化框架对比 | 质量工程

一、前言 自动化测试是把将手工驱动的测试行为转化为机器自动执行&#xff0c;通常操作是在某一框架下进行代码编写&#xff0c;实现用例自动发现与执行&#xff0c;托管在CI/CD平台上&#xff0c;通过条件触发或手工触发&#xff0c;进行回归测试&线上监控&#xff0c;代替…

opencv-python相机标定详解

文章目录 角点检测查看角点标定 opencv中内置了张正友的棋盘格标定法&#xff0c;通过一些姿态各异的棋盘格图像&#xff0c;就能标定相机的内外参数。 角点检测 第一步是角点检测&#xff0c;首先需要读取棋盘格图像 import numpy as np import cv2 import ospath imgs #…

一种Android应用的桌面图标隐藏方法

在Android10之前&#xff0c;应用程序通过调用PackageManager.setComponentEnabledSetting(componentName, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP)函数来实现图标隐藏。 但是在android10之后&#xff0c;所有带四大组件&#xff08…

RabbitMQ养成记 (6. spingboot 集成 rabbitMQ,生产者/消费者)

Springboot集成 搞springboot的那群人 不喜欢造轮子&#xff0c;就喜欢搞各种集成。 首先创建一个springboot项目&#xff1a; 之前我们在方法中 创建工厂类配置&#xff0c; 现在直接在application.yml 中配置即可&#xff1a; spring:rabbitmq:host: **********username:…

赢得浮生半日闲,内卷时代,我们需要怎样的智能科技?

哲学家罗泰戈拉说&#xff1a;“人是万物的尺度&#xff0c;是存在的事物存在的尺度。” 智能电器&#xff0c;究竟能为用户和市场提供什么样的价值&#xff1f;凭什么让消费者买单&#xff1f;毫无疑问&#xff0c;也应该以“人”为标尺。 今天&#xff0c;忙碌似乎成了现代人…

特征选择与特征提取

目录 一、 特征选择1、特征2、特征选择3、扩展——特征选择算法(有兴趣和精力可了解)拓展--完全搜索:拓展--启发式搜索:拓展--随机搜索:拓展--遗传算法: 二、 特征提取三、特征提取主要方法——PCA(主成分分析)1、PCA算法是如何实现的&#xff1f;PCA--零均值化&#xff08;中心…

Redis 概述

1. NoSQL 数据库简介 技术发展: 技术的分类 1、解决功能性的问题&#xff1a; Java、 Jsp、 RDBMS、 Tomcat、 HTML、 Linux、 JDBC、 SVN2、解决扩展性的问题&#xff1a; Struts、 Spring、 SpringMVC、 Hibernate、 Mybatis3、解决性能的问题&#xff1a; NoSQL、 Java 线…

从神经递质到网络:利用分子信息功能成像超越组织层级

导读 人脑在微观、介观和宏观尺度的组织原则上表现出复杂的相互作用。最近的协同多模态方法已经开始将微观尺度信息与系统水平的动力学联系起来&#xff0c;超越了组织层级&#xff0c;并为大脑的功能和功能障碍提供了新的视角。具体来说&#xff0c;可以将微观尺度特性&#…

HMI 自动生成技术讨论(1)

HMI 的信息模型 HMI 给人的基本印象就是一个设备控制面板&#xff0c;或者是控制室里电脑屏幕的图形控制界面。进入信息化时代&#xff0c;HMI 的需求越来越大&#xff0c;不仅仅是操作工人和运维人员需要HMI&#xff0c;集团公司&#xff0c;工厂&#xff0c;车间的管理人员&…

芯片封装技术(四)

集成电路芯片与封装之间是不可分割的整体。没有一个芯片可以不用封装就能正常工作&#xff0c;封装对芯片来说是必不可少的&#xff0c;随着IC生产技术的进步&#xff0c;封装技术也不断更新换代&#xff0c;每一代IC都与新一代的IC封装技术紧密相连。 一、什么是封装&#xf…

Qt文件系统源码分析—第二篇QFileInfo

深度 本文主要分析Windows平台&#xff0c;Mac、Linux暂不涉及 本文只分析到Win32 API/Windows Com组件/STL库函数层次&#xff0c;再下层代码不做探究 本文QT版本5.15.2 类关系图 QTemporaryFile继承QFile QFile、QSaveFile继承QFileDevice QFileDevice继承QIODevice Q…

考虑阶梯式碳交易机制与电制氢的综合能源系统热电优化

目录 1 主要内容 2 部分程序 3 程序结果 4 程序链接 1 主要内容 “双碳”背景下&#xff0c;为提高能源利用率&#xff0c;优化设备的运行灵活性&#xff0c;进一步降低综合能源系统&#xff08;IES&#xff09;的碳排放水平&#xff0c;提出一种IES低碳经济运行策略。首先…

【牛客刷题】笔试选择题整理(day1-day2)

每天都在进步呀 文章目录 1. 小数求模运算2. 进程的分区&#xff0c;这里说的不是JVM的分区。进程中&#xff0c;方法存放在方法区。3. 访问权限控制4. 继承与多态5. 与equals()6. 类加载顺序7. super()与this()7.1 super7.1.1 super调用父类构造方法7.1.2 super调用父类属性和…

Jabil EDI项目开源介绍

近期为了帮助广大用户更好地使用EDI系统&#xff0c;我们根据以往的项目实施经验&#xff0c;将成熟的EDI项目进行开源。用户安装好知行之桥EDI系统之后&#xff0c;只需要下载我们整理好的示例代码&#xff0c;并放置在知行之桥指定的工作区中&#xff0c;即可开始使用。 今天…