首页 > 其他分享 >面试总结篇--1

面试总结篇--1

时间:2024-09-26 22:51:01浏览次数:3  
标签:总结 调用 请求 订单 -- 面试 支付 序列化 加载

双亲委派机制

JVM可识别文件是一个个.class(字节码)文件,而这些.class需要运行起来需要JVM的类加载器将这些.class文件加载到内存,并对数据进行校检、转换、解析、初始化并最终形成可以被JVM直接执行的指令。

而JVM的类加载器去加载.class文件的时候所需要遵循的原则就是双亲委派原则。

双亲委派原则就是:一个类加载器在收到类的加载请求后不会立刻加载自己,而是先去让父类的加载器去查缓存中是否已经加载,层层迭代,到最顶层都没有加载,会往下进行委派,去加载指定的类。

双亲委派机制的好处:

  • 避免重复加载造成的资源浪费问题,父类已经加载了,子类就不需要再加载了
  • 保证了类加载器的安全性:解决了各个类加载器的基础类统一问题,如果不使用这种方式,那么用户可以随意定义类加载器加载核心API,会带来安全隐患。

什么是反射?

反射是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用他的任意一个属性和方法,这种动态获取信息以及动态调用对象的方法,称为Java的反射机制

反射的优缺点

优点: 可以动态执行,在运行期间根据业务功能动态的执行方法,访问属性,最大限度的发挥了Java的灵活性

缺点: 对性能有影响,这类操作总是慢于Java代码

反射的应用场景

  1. JDBC连接数据库,用到反射动态加载数据库驱动程序
  2. Web服务器利用反射调用SevLet的服务方法
  3. 很多框架都用反射机制,注入属性,调用方法

Session和Cookie的区别

  • cookie和session都是用来跟踪浏览器用户身份的会话方式
  • 存放数据的位置不同,cookie存放在客户端浏览器上,Session存放在服务器上
  • cookie不是很安全,别人可以分析存放在本地的cookie并进行cookie欺骗,如果考虑到安全因素应该使用session
  • session会在一定时间内保存在服务器上。当访问增多,会比较占用服务器的性能,如果考虑到减轻服务器的性能应该使用cookie
  • 单个cookie在客户端的限制是3k,就是说一个站点在客户端存放的cookie不能超过3k
  • 所以将登录信息等重要的信息存放为session,其他信息如果需要保留,放在cookie中

HashMap的底层原理

HashMap在JDK 1.7和JDK 1.8的主要区别包括以下几个方面:

数据结构的变化:

JDK 1.7:HashMap是基于数组+链表的形式实现,当哈希冲突严重时,多个键映射到同一个索引位置时,它们会形成一个链表。这种结构在哈希冲突较多时,查询效率较低。‌12

JDK 1.8:HashMap引入了红黑树来优化数据结构。当链表长度超过8时,链表会转换为红黑树,从而提高查询效率。这种变化使得HashMap在处理大量哈希冲突时性能更好。

扩容条件的变化:

JDK 1.7:当HashMap中的元素数量达到容量乘以负载因子(默认为0.75)时,会触发扩容操作,扩容后数组大小变为原来的两倍。‌13

JDK 1.8:扩容条件有所改进,不仅在初始化或size超过阈值时会触发扩容,还会在链表长度超过8时调用treeifyBin()方法进行扩容。

插入方式的变化:

JDK 1.7:HashMap使用头插法插入数据,这种方式在并发插入时可能导致循环链表的问题。‌13

JDK 1.8:改为尾插法插入数据,这种方式在并发场景下减少了线程间的竞争,提高了并发性能。

哈希冲突解决方式的变化:

JDK 1.7:当多个键映射到同一个索引位置时,它们会形成一个链表。查找键时,HashMap会遍历该链表,通过hashCode和equals方法判断是否为目标键。‌34

JDK 1.8:引入红黑树后,当链表长度超过8时,链表会转换为红黑树,从而提高查询效率。查找时间从O(n)变为O(logn)。

post和get请求的区别

1、GET请求,请求的数据会附加在URL之后,以?分割URL和传输数据,多个参数用&连接。URL的编码格式采用的是ASCII编码,而不是uniclde,即是说所有的非ASCII字符都要编码之后再传输。

POST请求:POST请求会把请求的数据放置在HTTP请求包的包体中。上面的item=bandsaw就是实际的传输数据。

因此,GET请求的数据会暴露在地址栏中,而POST请求则不会。

2、传输数据的大小

在HTTP规范中,没有对URL的长度和传输的数据大小进行限制。但是在实际开发过程中,对于GET,特定的浏览器和服务器对URL的长度有限制。因此,在使用GET请求时,传输数据会受到URL长度的限制。

对于POST,由于不是URL传值,理论上是不会受限制的,但是实际上各个服务器会规定对POST提交数据大小进行限制,Apache、IIS都有各自的配置。

3、安全性

POST的安全性比GET的高。这里的安全是指真正的安全,而不同于上面GET提到的安全方法中的安全,上面提到的安全仅仅是不修改服务器的数据。比如,在进行登录操作,通过GET请求,用户名和密码都会暴露再URL上,因为登录页面有可能被浏览器缓存以及其他人查看浏览器的历史记录的原因,此时的用户名和密码就很容易被他人拿到了。除此之外,GET请求提交的数据还可能会造成Cross-site request frogery(跨站请求伪造)攻击

序列化和反序列化

1、序列化:将Java对象转化为字节序列,可以存储在硬盘上,当JVM停机的时候,字节序列会在硬盘上继续等待

2、反序列化:将字节序列恢复为Java对象的过程,当JVM重启后,把序列化的字节序列通过反序列化恢复为Java对象。

核心就是:对象状态的保存和重建

序列化成字节流形式的对象可以进行网络传输, 通过序列化可以在进程之间传递对象。

  • serialVersionUID是序列化前后的唯一标识符
  • 默认如果没有人为显式定义过serialVersionUID,那编译器会为它自动声明一个!
  • 凡是实现Serializable接口的类都有一个表示序列化版本标识符的静态变量。在完成序列化后,java编译器会自动给这个class进行一个摘要算法,类似于指纹算法,只要文件发生任何改变,得到的UID就会不一样。那么可能由于我们对序列化对象的修改,比如增加某个属性,就会导致反序列化报错。
  • 要解决这样的问题,serialVersionUID 就派上用场了,只要在javaBean对象中增加一个serialVersionUID 字段,用来标识这个类,而不是由编译器自动生成,这样当我们修改这个类时,反序列化就不会报错了。

两种特殊情况

凡是被static修饰的字段是不会被序列化的

凡是被transient修饰符修饰的字段也是不会被序列化的

对于第一个,因为序列化保存的是对象的状态而非类的状态,所以会忽略static静态域。

对于第二个,就需要了解transient修饰符的作用了

如果在序列化某个类的对象时,就是不希望某个字段被序列化(比如这个字段存放的是隐私值,如:密码等),那这时就可以用transient修饰符来修饰该字段。

实现序列化反序列化

  • 使用JDK自带的API

java.io.ObjectOutputStream对象输出流,调用writeObject(Object obj)方法可以将obj对象进行序列化,把得到的字节序列写到一个目标输出流中。下面是以文件输出流为例子。

java.io.ObjectInputStream对象输入流,调用readObject(Object obj)方法从一个源输入流中读取字节序列,再把字节序列反序列为一个对象,并将对象返回。

  • 实现序列化和反序列化的工具类:ObjSerializeAndDeserialize
  • 使用第三方工具Gson

接口幂等性

就是用户进行同一操作发送多次请求返回的结果是一致的,不会因为多次点击产生副作用。

解决方案:

1.token+redis 机制

比如订单支付场景:

该支付分为两个步骤:

1.1 获取全局唯一token

接口处理生成唯一标识(token) 存储到redis中,并返回给调用客户端。

1.2 发起支付操作并附带token

接口处理:

1.2.1 获得分布式锁(处理并发情况)

1.2.2 判断redis中是否存在token

1.2.3 存在 执行支付业务逻辑,否则返回该订单已经支付

1.2.4 释放分布式锁

思考:为什么要加分布式锁?

原因1:在高并发请求中 ,token判断是否存在是非线程安全的,所以要加分布式锁来保证 该条件的判断为线程安全

注释:也可redis用删除操作来判断token,删除成功代表token校验通过 这个删除是原子操作的

原因2:在支付业务中,判断支付订单是否已经存在,存在说明该订单已经支付过了,不存在就执行扣款操作,如果相同操作并发两个请求来到判断条件可能两个请求都能判断支付订单不存在,造成重复扣款。 所以也要加分布式锁保证线程的安全。

2.CAS 保证接口幂等性

2.1 状态机制幂等(状态不可逆)

针对更新操作:

例如 电商订单,订单支付状态 0 待支付 , 1 支付中 , 3 支付成功 4 支付失败。

update order set status = 1 where status =0 and orderId = “201251487987”

该sql语句利用状态CAS 保证该操作的幂等。

eg:比如要进行订单支付,上来先用CAS更新订单状态,

返回影响说为1 代表修改成功,可以支付,继续执行支付业务代码

返回影响数 0 代表修改失败,该订单已经不是待支付订单了。

注释:实际这里是利用CAS原理

3 乐观锁实现幂等

背景由来:

为什么要有幂等这种场景?因为在大的系统中,都是分布式部署,如:订单业务 和 库存业务有可能都是独立部署的,都是单独的服务。用户下订单,会调用到订单服务和库存服务。

比如:订单系统:

订单服务 —> 库存服务 (PRC远程调用(服务接口))

因为分布式部署,很有可能在调用库存服务时,因为网络等原因,订单服务调用失败,但其实库存服务已经处理完成,只是返回给订单服务处理结果时出现了异常。这个时候一般系统会作补偿方案,也就是订单服务再此放起库存服务的调用,库存减1

update t_goods set count = count -1 where good_id=2

这样就出现了问题,其实上一次调用已经减了1,只是订单服务没有收到处理结果。现在又调用一次,又要减1,这样就不符合业务了,多扣了。

幂等这个概念就是,不管库存服务在相同条件下调用几次,处理结果都一样。这样才能保证补偿方案的可行性。

乐观锁方案

借鉴数据库的乐观锁机制,如:

update t_goods set count = count -1 , version = version + 1 where good_id=2 and version = 1

4 防重表

1.利用数据库建一张防重表(加唯一索引)

比如订单支付,

反正重复支付:订单号插入防重表 成功 执行支付业务逻辑,失败说明已经支付过。

防重表支付成功是否要删除:

1.可定期清除数据

2.也可结合 订单状态 ,在支付前查询订单状态为待支付 执行支付操作 ,操作后删除订单号 若 第二个请求插入防重表成功,但是这个时候查询订单状态失败。

(实际这个防重表就是实现了分布式锁)

5. 缓存队列

将请求放入队列,后续使用异步任务处理队列中的数据,过滤掉重复的消息。 和防止重复消费道理是一样。

class Sale{
    private int number=30;

    public synchronized void saleTicket(){
        while(number!=0){
            System.out.println(Thread.currentThread().getName());
        }
    
    }
}
public class ThreadTest{
    public static void main(String[] args){
        Sale sale = new Sale();

        new Thread(()->{
            for(int i = 0; i < 40; i++){
                sale.saleTicket();
            }
        },"AA").start();

        new Thread(()->{
            for(int i = 0; i < 40; i++){
                sale.saleTicket();
            }
        },"BB").start();

        new Thread(()->{
            for(int i = 0; i < 40; i++){
                sale.saleTicket();
            }
        },"CC").start();
    }
}
class Sale{
    private int number = 30;

    public void saleTicket(){
        Lock lock = new Lock();
        lock.lock();
        try{
            while(number != 0){
                System.out.printlln(Thread.currentThread().getName());
            }
        }finally{
            lock.unlock();
        }
        
    }
}
public class ThreadTest{
    public static void main(String[] args){
        Sale sale = new Sale();
        new Thread(()->{
            for(int i = 0; i < 40;i++){
                sale.saleTicket();
            }
        },"AA").start();
        new Thread(()->{
            for(int i = 0; i < 40;i++){
                sale.saleTicket();
            }
        },"BB").start();
        new Thread(()->{
            for(int i = 0; i < 40;i++){
                sale.saleTicket();
            }
        },"CC").start();
    }
}

Lock锁在资源竞争激烈的情况下性能比synchronize锁好。‌

Lock锁和synchronize锁各有其适用场景和优势。‌Lock锁提供了更多的灵活性和可扩展性,‌允许以非阻塞的方式获取锁,‌并且在资源竞争激烈的情况下表现出更好的性能。‌相比之下,‌synchronize锁虽然编码更简单,‌锁机制由JVM维护,‌在竞争不激烈的情况下性能更好,‌但它会根据锁的竞争情况从偏向锁升级到轻量级锁再到重量级锁。‌这种升级过程在高度竞争的环境中可能会导致性能下降12。‌

Lock锁需要手动调用lock()方法获取锁,‌并在finally块中调用unlock()方法释放锁,‌这种机制在资源竞争激烈时能够提供更好的性能,‌因为它允许更精细的控制和避免不必要的等待。‌而synchronize锁的获取和释放由JVM自动完成,‌虽然简化了编程,‌但在高并发场景下可能不如Lock锁高效23。‌

总的来说,‌选择使用哪种同步机制应根据具体的并发需求和性能要求来决定。‌如果预计会有高并发和激烈的资源竞争,‌Lock锁可能是更合适的选择。‌如果并发需求不高,‌或者希望代码编写更简洁,‌synchronize锁可能更适合12。‌

标签:总结,调用,请求,订单,--,面试,支付,序列化,加载
From: https://blog.csdn.net/qq_43583691/article/details/142555132

相关文章

  • 一篇文章讲清楚synchronized关键字的作用及原理
    概述在应用Sychronized关键字时需要把握如下注意点:一把锁只能同时被一个线程获取,没有获得锁的线程只能等待;每个实例都对应有自己的一把锁(this),不同实例之间互不影响;例外:锁对象是*.class以及synchronized修饰的是static方法的时候,所有对象公用同一把锁synchronized修饰......
  • 易优CMS安装程序的时候提示数据库版本与程序不符怎么办?-eyoucms
    当安装程序时提示数据库版本与程序不符,通常是因为当前数据库版本高于程序所支持的版本,或者程序与数据库之间存在不兼容的情况。解决这类问题的方法有以下几种:升级程序版本如果数据库版本较高,而程序版本较低,最简单的方法是升级程序版本。根据提示信息,如果数据库版本为1.5.1而......
  • 初学Java基础Day07---while循环,do-while循环,特殊流程孔子语句,Java循环习题
    一,while循环1.语法结构:while(表达式){....代码块/循环体.....}2.理解:        表达式的结果必须是boolean类型,true---执行代码块,false--跳出循环体3.案例//案例:用while循环,打印五遍HelloWorldinti=1;while(i<=5){System.out.println("HelloWorld");......
  • MySQL 中优化 COUNT()查询的实用指南
    在MySQL数据库的使用中,我们经常会用到COUNT()函数来统计行数或满足特定条件的行数。然而,在处理大规模数据时,COUNT()查询可能会变得非常缓慢,影响数据库的性能。那么,如何在MySQL中优化COUNT()查询呢?本文将为你介绍一些实用的方法。一、COUNT()函数的基本用法COUNT()函数是My......
  • 进击的奶牛题解
    题目描述FarmerJohn建造了一个有 N(2≤N≤105)个隔间的牛棚,这些隔间分布在一条直线上,坐标是 x1,x2,⋯ ,xN​(0≤xi≤109)。他的 C(2≤C≤N)头牛不满于隔间的位置分布,它们为牛棚里其他的牛的存在而愤怒。为了防止牛之间的互相打斗,FarmerJohn想把这些牛安置在指定的隔间,所......
  • 智界R7订单爆了,它凭什么抢了Model Y的风头?
    作者|曾响铃文|响铃说鸿蒙智行的又一个爆款稳了。9月24日,智界R7正式上市,早在9月10日已开启小订的它,到上市当天小订数已经突破30000台。上市24小时大定数突破6000台。这一成绩殊不简单,要知道,智界R7所走的轿跑SUV路线,本身是一个非常小众的市场,除了ModelY销量一枝独秀,其他玩家都......
  • 01 重点 导入模块练习题
    练习1:client飘红可以导入原因:因为当前运行的run.py文件,此时当前目录下面的所有文件都会自动增加到sys.path里面,此时bin目录下面的所有模块都可以导入重点。练习2:#在排除pycharm操作下,此场景下在终端运行run.py文件中,不能导入x方法。原因:s21test路径没有导入到sys.path......
  • 奶牛分厩题解
    题目描述农夫约翰有 N(1≤N≤5000)头奶牛,每头奶牛都有一个唯一的不同于其它奶牛的编号 s[i],所有的奶牛都睡在一个有 K 个厩的谷仓中,厩的编号为 00 到 K−1。每头奶牛都知道自己该睡在哪一个厩中,因为约翰教会了它们做除法,Si mod K的值就是第 i 头奶年所睡的厩的编......
  • 易优CMS为何我安装完提示这个报错?:Array and string offset access syntax with curly
    当你遇到类似 Arrayandstringoffsetaccesssyntaxwithcurlybracesisdeprecated 的报错时,通常是因为当前使用的PHP版本较高,而程序代码中使用了一些已弃用的语法。原因分析PHP版本过高:当前使用的PHP版本(如PHP7.4或更高版本)不再支持某些旧的语法形式。代码使......
  • FC-28土壤湿度传感器
        FC-28土壤湿度传感器是一种用于测量土壤中水分含量的传感器。以下是关于它的详细介绍:一、基本特点:双输出模式:具有模拟输出(AO)和数字输出(DO)两种模式。模拟输出可以提供连续的、更精确的湿度数值变化;数字输出则是简单的高低电平信号,可用于判断湿度是否超过设定的......