java程序员的金三银四求职宝典

面试题解析

最主要的还是面试题的解析,但是前提是你有这个资格入得了xxx公司的法眼才行,就是说教育背景啥的。废话不多说,开放面试题……

1、ReentrantLock的可重入是怎么实现的?

答:

2、怎么理解http的无状态?

答:浏览器不会去记录是谁去访问了它,这就是无状态,即使你访问多次浏览器也不记得Websocekt有状态,也可以使用cookie+session+http实现有状态的http。可以对比http和websocket的优缺点,为啥不适用websocket?

  1. websocket目的就是解决网络传输中的双向通信的问题,http1.1默认是持久连接

Cookie和session区别:

Cookie(是key和value形式存储)工作原理:

  1. 浏览器第一次发送请求到服务器端;
  2. 服务器端创建cookie,该cookie中包含用户的信息,然后将该cookie发送到浏览器端;
  3. 浏览器端再次访问服务器端时会携带服务器端创建的cookie;
  4. 服务器端通过cookie中携带的数据区分不同的用户。
  1. cookie数据保存在客户端,session数据保存在服务器端;
  2. Cookie不是很安全,别人可以分析存放在本地的cookie并进行cookie欺骗,如果主要考虑安全应当使用session;
  3. Session会在一定时间内保存在服务器上。当访问量增多,会比较占用服务器的资源,如果主要考虑减轻服务器性能方面,应当使用cookie;
  4. 单个cookie在客户端的限制是4k,就是说一个站点在客户端存放的cookie不能4K;

3、多线程是什么?为什么会有多线程问题?

答:单线程程序只能顺序执行,并发性低;多线程就可以解决这个问题。但是多个线程会导致竞争资源、死锁、内存泄露等问题。

4、GC机制

答:GC是垃圾回收的机制。将不在使用的对象从内存中释放出来。哪些对象需要回收?引用计数进行判断、或者可达性分析。流行的都是用可达性分析进行回收对象的。

5、Hashmap原理

答:1.7之前hashmap底层是数组和链表,1.7之后是数组+链表+红黑树。初始化默认数组长度为16,扩容因子=0.75,就是说当数组元素超过数组大小的0.75倍后就会自动扩容,扩容倍数为2。

6、Bean的生命周期

答:

7、IoC和AOP使用场景

答:Ioc是控制反转,是一个创建、管理bean的容器。实现IoC的三种注入方式:构造器、setter、接口

Spring中有BeanFactory和ApplicationContext两个IOC容器。ApplicationContext接口扩展了BeanFactory接口。

IOC好处:1、最小化应用程序的代码量;2、使得应用程序易于测试;3、松耦合;4、支持即时的实例化和延迟加载服务。

IOC的实现原理就是工厂模式加反射机制。

Spring提供了三种配置方式:xml、注解、java代码。

AOP是将其他公共的功能从业务层剥离出来。比如:日志、事务和异常。AOP是使用动态代理实现的,就是在内存中创建一个临时的AOP代理对象,并且在特定的切点上做了增强。

8、多线程使用场景,线程池、参数、拒绝策略

答:多线程适用于需要并发执行任务的场景,这样可以提高程序的性能和效率。线程之间的频繁切换是会浪费资源的。

程序的运行,本质上就是占用系统资源。那优化资源的技术是啥呢?--->就是线程池。

线程池的好处:降低资源的消耗、复用、方便管理。

Java中不允许使用Executors去创建线程,而是通过ThreadPoolExecutor的方式。目的是明确线程池的运行规则。

Java中有如下线程池创建方法:单一线程池、固定线程池、可伸缩线程池、定时线程池

线程池中七大参数:核心线程数、最大线程数、拒绝策略、阻塞队列、线程工厂、超时等待时间、超时等待时间单位

拒绝策略触发时机:当提交的任务数大于阻塞队列+最大线程数。

四种拒绝策略:

  1. 默认策略,直接抛出异常;
  2. 不处理任务,直接丢弃;
  3. 将等待队列的队首任务丢弃,并执行当前任务;
  4. 由调用线程处理该任务。

超时等待时间是针对最大线程数中的非核心线程的。

9、锁、乐观锁、悲观锁、独占锁(排他锁)、共享锁

答:

乐观锁适合读多写少的场景。乐观锁更新方式认为:在更新数据的时候其他线程争抢这个共享变量的概率很小,所以更新数据的时候不会对共享数据加锁。但是在正式更新数据之前会检查数据是否被其他线程改变过,如果未被其他线程改变过就将共享变量更新成为最新值,如果发现共享变量已经被其他线程更新过了,就重试,直到成功为止。CAS机制就是乐观锁的典型实现。

或:当多个线程尝试使用 CAS 同时更新 同一个变量时,只有其中一个线程能更新变量的值,而其它线程都失败,失败的 线程并不会被挂起,而是被告知这次竞争中失败,并可以再次尝试。

共享锁(S锁):共享锁用于不更改或不更新数据的操作(只读操作),如select语句;如果事务T对数据A加上共享锁后,则其他事务只能对A再加共享锁,不能加排他锁。获准共享锁的事务只能读数据,不能修改数据。

独占锁(排他锁)(X锁):用于数据修改操作,例如insert、update或者delete。确保不会同时同一资源进行多重更新。如果事务T对数据A加上排他锁后,则其他事务不能再对A加任何类型的锁。获准排他锁的事务既能读数据,又能修改数据。

10、@Autowired和@Resource区别

答:

  1. @Autowired是按类型装配的,@Resource是按名称装配的。
  2. @Autowired注解是spring提供的,@Resource是J2EE提供的。

11、事务,四大特性

答:

12、什么是索引?索引的分类?索引失效场景?

答:

索引就是数据结构,使用数据结构将数据连接起来的。

索引分为:主键、唯一、常规、全文、聚集、非聚集索引

索引失效场景:

  1. 不满足最左匹配原则(联合索引);
  2. 使用select *;
  3. 索引列上有计算;
  4. 索引列用了函数;
  5. 字段类型不同;
  6. Like左边包含了%

13、Redis缓存穿透、缓存雪崩?持久化方式?

答:

14、简单实现一个分布式锁?

答:

15、单例模式写一下?

答:单例模式的编写注意事项:1、构造函数的私有化;2、自行对外提供实例;3、对外提供一个公共的获取该实例的方法。

有懒汉式的单例模式(容易造成多线程的问题、所以需要加锁synchronized)还有饿汉式的单例模式。

懒汉式就是你用的时候我在加载,饿汉式就是类加载的时候我就加载。

使用synchronized的懒汉式单例模式还是会有问题:因为synchronized的范围太大,颗粒度比较大,这个会是成为系统的瓶颈。所以还需要进一步升级----->使用双重校验锁的方式。

但是双重校验锁的方式还是会有问题:指令重排的问题。指令重排就是JVM在优化指令时,不影响单线程执行结果的前提下,提高并行度。

singleton = new Singleton()看似时原子操作,其实可以分为以下三步:

1、分配对象内存空间

2、初始化对象;

3、设置实例指向刚分配的内存地址;

操作2依赖操作1,但是操作3不依赖上述操作。所以JVM可以对上述指令进行重排的,重排如下:

  1. 分配对象内存空间
  2. 设置实例指向刚分配的内存地址,此时对象还未初始化;

3初始化对象;

当线程A执行这段指令时,执行到2时,对象还未初始化,就赋值引用了,恰好线程B进行判断对象的引用不为空,然后就返回对象进行使用了,最后程序报错了。

16、为什么innodb选择B+树做索引?

答:回答此问题就和其他几个索引做对比即可。

相较于B树:B树的叶子节点和非叶子节点都存储数据和指针,最后会导致树的高度变高

相较于二叉树:树的高度低,速度快

相较于hash索引:可以范围查询、也会hash冲突

17、索引的分类、聚集索引和非聚集索引(二级索引)

索引分为四类:

主键索引:就是只能有一个;

唯一索引:可以有多个(猛一听以为只能有一个,其实它这个唯一的意思是在表中的某一列数据不能重复而已);

常规索引:可以有多个(快速定位特殊数据,就是平常我们建立的索引);

全文索引:是查找文本中的关键字,而不是比较索引的值,可以有多个。

聚集索引:就是索引和数据在一块---innodb就是,效率高

非聚集索引(二级索引):就是索引和数据单独存储---myisam,效率低

18、Spring事务失效场景?

答:spring事务底层使用了AOP动态代理实现的。同一事务表示指同一数据库连接,只有拥有同一个数据库连接才能同时提交和回滚。

  1. 访问修饰符错误,只有在public的方法上加事务注解才可以;
  2. 使用final加在添加注解事务的方法上;
  3. 在方法内部调用带有事务的方法(原因:方法B调用带有事务的方法A,它们在同一个类中。由于这两个方法都是同一个实例内部调用的,spring的默认代理是CGlib代理。这种情况下,方法A调用是不会经过代理的,因此事务会失效的。解决方法:写成两个类。);
  4. 未被spring管理;
  5. 多线程调用(不同数据库,不同事务);
  6. ……

19、线程池大小怎么设置?

答:线程池设置较小,会导致很多任务没有线程处理,最后JVM就会及逆行垃圾回收;线程池设置较大,会导致多线程竞争CPU资源,使得线程切换频繁,导致性能降低。

如果任务是CPU密集任务:主要消耗CPU资源,那么线程池大小就设置为CPU核心数+1,目的是防止某些原因导致线程阻塞而带来的影响。一旦某个线程被 阻塞,释放了CPU资源,而这种情况多出来的线程就可以利用CPU资源了。

如果任务是IO密集任务:线程池大小设置为2N。因为系统的大部分的时间都在处理IO操作此时线程可能阻塞,释放CPU资源,这时候就可以将CPU资源交给其他线程使用。

20、怎么判断线程池的任务是否执行完毕了?

  1. 适用于线程池的原生函数isTerminated();
  2. 使用重入锁,维持一个公共计数;
  3. 使用CountDownLatch;
  4. submit'向线程池提交任务,使用Future判断任务执行状态。

以上面试题是我在面试过程中的总结,有些没有答案是因为我不会或者我觉得太简单了。如果你也知道,打在评论区我们讨论一下 ~

后续我会继续分享我的面试题的,今天时间有限,我要下班了,再见!

  • 23
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值