Java秋招面试相关

Java常见异常

算术异常类:ArithmeticExecption

空指针异常类:NullPointerException

类型强制转换异常:ClassCastException

数组下标越界异常:ArrayIndexOutOfBoundsException

文件未找到异常:FileNotFoundException

字符串转换为数字异常:NumberFormatException

类未找到异常:ClassNotFoundException

方法未找到异常:NoSuchMethodException

分布式架构节点

节点角色说明
Provider暴露服务的服务提供方
Consumer调用远程服务的服务消费方
Registry服务注册与发现的注册中心
Monitor统计服务的调用次数和调用时间的监控中心
Container服务运行容器

 

HashSet的初始化会进行什么操作

创建一个HashSet会进行new一个HashMap

HashSet实现Set接口,由哈希表(实际上是一个HashMap实例)支持。它不保证set 的迭代顺序;特别是它不保证该顺序恒久不

变,此类允许使用null元素。 

在HashSet中,元素都存到HashMap键值对的Key上面,而Value时有一个统一的值private static final Object PRESENT =

new Object();,(定义一个虚拟的Object对象作为HashMap的value,将此对象定义为static final。)

Redis为什么快

1、完全基于内存,绝大部分请求是纯粹的内存操作,非常快速。数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1);

2、数据结构简单,对数据操作也简单,Redis中的数据结构是专门进行设计的;

3、采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗 CPU,不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗;

4、使用多路I/O复用模型,非阻塞IO;

5、使用底层模型不同,它们之间底层实现方式以及与客户端之间通信的应用协议不一样,Redis直接自己构建了VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求;

分布式幂等性问题

幂等操作:是其任意多次执行所产生的影响均与一次执行的影响相同(不用担心重复执行会对系统造成改变)

幂等性解决方案

1.数据库表加唯一索引,防止新增脏数据。

比如对订单号进行加唯一索引,防止生成重复订单。

如果不加索引的后果是:当根据订单号去支付,支付表生成两条重复的订单号,然后去支付宝、微信、易宝支付去支付,付款

成后,第三方异步回调接口,本地接口首先根据订单号查询实体,发现查询到两条,系统就会抛出异常。

2.分布式锁

利用redis,在业务系统插入数据或者更新数据,获取分布式锁,然后做操作,之后释放锁,这样其实是把多线程并发的锁的思路

3.token机制,防止重复提交

a. 数据提交前要向服务的申请token,token放到redis中,token有效时间 

b. 提交后后台校验token,同时删除token,生成新的token返回 

分布式的弊端

  1. 架构设计变得复杂(尤其是其中的分布式事务)
  2. 部署单个服务会比较快,但是如果一次部署需要多个服务,部署会变得复杂
  3. 系统的吞吐量会变大,但是响应时间会变长
  4. 运维复杂度会因为服务变多而变得很复杂
  5. 架构复杂导致学习曲线变大
  6. 测试和查错的复杂度增大
  7. 技术可以很多样,这会带来维护和运维的复杂度
  8. 管理分布式系统中的服务和调度变得困难和复杂

什么时候需要使用索引,什么时候不需要

索引的优缺点,何时用或不用索引

什么时候需要创建索引

  • 主键自动建立唯一索引

  • 频繁作为查询条件的字段应该创建索引

  • 查询中排序的字段创建索引将大大提高排序的速度(索引就是排序加快速查找

  • 查询中统计或者分组的字段;

什么时候不需要创建索引

  • 频繁更新的字段不适合创建索引,因为每次更新不单单是更新记录,还会更新索引,保存索引文件

  • where条件里用不到的字段,不创建索引;

  • 表记录太少,不需要创建索引;

  • 经常增删改的表;

  • 数据重复且分布平均的字段,因此为经常查询的和经常排序的字段建立索引。注意某些数据包含大量重复数据,因此他建立索引就没有太大的效果,例如性别字段,只有男女,不适合建立索引。

什么时候需要用存储过程

1.存储过程只在创造时进行编译,以后每次执行存储过程都不需再重新编译,而一般SQL 语句每执行一次就编译一次所以使用存

储过程可提高数据库执行速度。

2.当对数据库进行复杂操作时(如对多个表进行Update,Insert,Query,Delete 时)可将此复杂操作用存储过程封装起来与数据库提

供的事务处理结合一起使用。这些操作,如果用程序来完成,就变成了一条条的SQL 语句,可能要多次连接数据库。而换成存

储,只需要连接一次数据库就可以了。

3.存储过程可以重复使用:可减少数据库开发人员的工作量。

4.安全性高:可设定只有某此用户才具有对指定存储过程的使用权。

5.更强的适应性:由于存储过程对数据库的访问是通过存储过程来进行的,因此数据库开发人员可以在不改动存储过程接口的情

况下对数据库进行任何改动,而这些改动不会对应用程序造成影响。

6.分布式工作:应用程序和数据库的编码工作可以分别独立进行,而不会相互压制。一般来说,存储过程的编写比基本SQL语句

复杂,编写存储过程需要更高的技能,更丰富的经验。

MySql查询语句的执行流程

权限校验(如果命中缓存)-> 查询缓存 -> 分析器 -> 优化器 -> 权限校验 -> 执行器 -> 引擎

MySql更新语句的执行流程

分析器 -> 权限校验 -> 执行器 -> 引擎 -> redo log(prepare状态)-> binlod -> redo log(commit状态) 

如何合理设置线程池大小

1、CPU密集型

尽量使用较小的线程池,一般CPU核心数+1

因为CPU密集型任务CPU的使用率很高,若开过多的线程,只能增加线程上下文的切换次数,带来额外的开销

2、IO密集型

方法一:可以使用较大的线程池,一般CPU核心数 * 2

IO密集型CPU使用率不高,可以让CPU等待IO的时候处理别的任务,充分利用cpu时间

方法二:线程等待时间所占比例越高,需要越多线程。线程CPU时间所占比例越高,需要越少线程。
下面举个例子:
比如平均每个线程CPU运行时间为0.5s,而线程等待时间(非CPU运行时间,比如IO)为1.5s,CPU核心数为8,那么根据上面这个公式估算得到:((0.5+1.5)/0.5)*8=32。这个公式进一步转化为:
最佳线程数目 = (线程等待时间与线程CPU时间之比 + 1)* CPU数目

3、混合型

可以将任务分为CPU密集型和IO密集型,然后分别使用不同的线程池去处理,按情况而定

一次完整的HTTP请求过程

1.对www.baidu.com这个网址进行DNS域名解析,得到对应的IP地址

2.根据这个IP,找到对应的服务器,发起TCP的三次握手

3.建立TCP连接后发起HTTP请求

4.服务器响应HTTP请求,浏览器得到html代码

5.浏览器解析html代码,并请求html代码中的资源(如js、css图片等)(先得到html代码,才能去找这些资源)

6.浏览器对页面进行渲染呈现给用户

7.断开TCP连接

浅拷贝和深拷贝的区别及实现

Java 浅拷贝和深拷贝的理解和实现方式

浅拷贝只是复制了对象的引用地址,两个对象指向同一个内存地址,所以修改其中任意的值,另一个值都会随之变化

a 通过拷贝构造方法实现浅拷贝

b 通过重写clone()方法实现浅拷贝

深拷贝是将对象及值复制过来,两个对象修改其中任意的值另一个值不会改变

a 通过重写clone方法来实现深拷贝

b 通过对象序列化实现深拷贝

头插法实现链表反转

public ListNode ReverseList(ListNode head) {
    ListNode newList = new ListNode(-1);
    while (head != null) {
        ListNode next = head.next;
        head.next = newList.next;
        newList.next = head;
        head = next;
    }
    return newList.next;
}

Java创建进程及进程同步

//如何用java语言开启一个进程
public class ProcessDemo {
    public static void main(String[] args) throws IOException{
        //方式一:使用Runtime的exec方法
        Runtime.getRuntime().exec("notepad");
        //方式二:使用ProcessBuilder类中的start方法
        ProcessBuilder pb = new ProcessBuilder("notepad");
        pb.start();
    }
}

解决进程同步

1 文件锁

//文件锁的简单实现方法
RandomAccessFile raf=new RandomAccessFile("c:/aa.txt","rw");
FileLock lock=raf.getChannel().lock();
        //需要同步的代码
lock.release();

2 使用数据库锁或者第三方获取锁的服务器。如果想进程之间共享数据,可以把数据放到数据库中进行共享。

数据库优化

为什么要优化

  • 系统的吞吐量瓶颈往往出现在数据库的访问速度上
  • 随着应用程序的运行,数据库的中的数据会越来越多,处理时间会相应变慢
  • 数据是存放在磁盘上的,读写速度无法和内存相比

如何优化

  • 设计数据库时:数据库表、字段的设计,存储引擎
  • 利用好MySQL自身提供的功能,如索引等
  • 横向扩展:MySQL集群、负载均衡、读写分离
  • SQL语句的优化(收效甚微)

Redis数据类型及数据结构

Redis数据类型

String

List

Hash

Set

ZSet

底层数据结构

数组

双向链表

二维结构

第一维度:数组

第二维度:链表

Hash

Hash+跳跃表

为什么要使用消息队列MQ

为什么要使用消息队列?

线程池的七个参数及含义

  • corePoolSize: 线程池核心线程数
  • maximumPoolSize:线程池最大数
  • keepAliveTime: 空闲线程存活时间
  • unit: 时间单位
  • workQueue: 线程池所使用的缓冲队列
  • threadFactory:线程池创建线程使用的工厂
  • handler: 线程池对拒绝任务的处理策略

线程池的四种拒绝策略

  • ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。 
  • ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。 
  • ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,执行后面的任务
  • ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务 

B-树的特征:

  • 根结点至少有两个子女。

  • 每个中间节点都包含k-1个元素和k个孩子,其中 m/2 <= k <= m

  • 每一个叶子节点都包含k-1个元素,其中 m/2 <= k <= m

  • 所有的叶子结点都位于同一层。

  • 每个节点中的元素从小到大排列,节点当中k-1个元素正好是k个孩子包含的元素的值域分划。

B+树的特征:

  • 有k个子树的中间节点包含有k个元素(B树中是k-1个元素),每个元素不保存数据,只用来索引,所有数据都保存在叶子节点。

  • 所有的叶子结点中包含了全部元素的信息,及指向含这些元素记录的指针,且叶子结点本身依关键字的大小自小而大顺序链接。

  • 所有的中间节点元素都同时存在于子节点,在子节点元素中是最大(或最小)元素。

B+树的优势:

  • 单一节点存储更多的元素,使得查询的IO次数更少。

  • 所有查询都要查找到叶子节点,查询性能稳定。

  • 所有叶子节点形成有序链表,便于范围查询。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值