java知识点-面试

HashMap扩容时,直接将数据从原数组平移到新数组可以吗

不可以;首先hashmap获取下标是通过hashcode&(n-1);当n长度发生变化时候;如果直接平移到新数组;下标也会发生变化;这样就无法通过index获取对应的value;

Java内存模型(JMM)

what?
java内存模型主要是定义程序中各种变量的访问规则;是一种抽象;
规定所有的变量必须存储在主内存(抽象);每条线程有自己的工作内存;线程工作内存保存了该线程使用的主内存副本;线程对变量的所有操作必须在工作内存进行,而不能直接读写主内存的数据;不同线程直接也无法直接访问对方工作内存里的内容;

Volatile

使用场景:
运算结果不依赖当前变量的值,或者能够保证只有单一的线程修改变量的值;
变量不需要与其他的状态变量共同参与不变约束。

volatile boolean shutDownBoolean;
public void shutdonw(){
shutDownBoolean=true;
}
public void doWork(){
  while(!shutDownBoolean){
  	  //业务代码
  }
}

禁止指令重排
long double 64位的读写操作 java允许虚拟机自己决定分为二次32位的读写;或者是一次保证原子性;

线程调度

线程调度是指 为线程分配处理器使用权的过程;主要有以下二种;协同式线程调度和抢占式线程调度;
协同式调度是指线程执行时间由线程自身控制,线程自己的工作执行完了之后,要主动通知等待系统切换到另一个线程上去;优点:简单,切换对线程自己是可知的,一般不存在线程同步的问题;
缺点:线程执行时间不可控制,如果一个线程的代码有问题;一直不告诉系统进行线程切换;就会一直阻塞;

抢占式调度:
系统分配时间;不是由线程自身控制;

Java中对象创建的几种方式。

创建对象的方式有四种:

  • 用new关键字创建。

User user = new User();

  • 调用对象的clone方法。
  • 利用反射,调用Class类的或者是Constructor类的newInstance()方法。

User user = User.class.newInstance();
或者是

Constructor constructor =User.class.getConstructor();
User user= constructor.newInstance();

  • 用反序列化,调用ObjectInputStream类的readObject()方法。

Minor GC和Full GC的触发条件。

  • Minor GC触发条件:当Eden区满时,触发Minor GC。

  • Full GC触发条件:

调用System.gc时,系统建议执行Full GC,但是不必然执行。
老年代空间不足。
方法区空间不足。
concurrent mode failure,当执行CMS GC过程时(“标记-清除”,存在内存碎片),同时有对象要放入老年代,而此时老年代空间不足造成的(有时候“空间不足”是CMS GC时当前的浮动垃圾过多导致暂时性的空间不足触发Full GC)。

Mysql 索引失效

1、索引上进行任何操作(计算,函数,自动类型转换)
2、使用范围条件(between,<,>,in等)右边的列;
3、使用 (!=)判断;Is null/is not null;使用or判断;
4、使用like通配符开头匹配;%ab会失效;ab%不会失效;

Java中的检查型异常和非检查型异常有什么区别

检查型异常和非检查型异常的主要区别在于其处理方式。检查型异常需要使用try, catch和finally关键字在编译期进行处理,否则会出现编译器会报错。对于非检查型异常则不需要这样做。Java中所有继承自java.lang.Exception类的异常都是检查型异常,所有继承自RuntimeException的异常都被称为非检查型异常。

内存泄漏与内存溢出的区别?

内存泄露:是指无用对象(不再使用的对象)持续占有内存或无用对象的内存得不到及时释放,从而造成的内存空间的浪费称为内存泄露。内存泄露有时不严重且不易察觉,这样开发者就不知道存在内存泄露,但有时也会很严重,会提示 Out of memory。
内存溢出:指程序运行过程中无法申请到足够的内存而导致的一种错误。内存泄露是内存溢出的一种诱因,不是唯一因素   那么,Java 内存泄露根本原因是什么呢?长生命周期的对象持有短生命周期对象的引用就很可能发生内存泄露,尽管短生命周期对象已经不再需要,但是因为长生命周期对象持有它的引用而导致不能被回收,这就是 Java 中内存泄露的发生场景

BIO、NIO、AIO的真正区别?

同步阻塞IO(BIO):用户进程发起一个IO操作以后,必须等待IO操作的真正完成后,才能继续运行;
同步非阻塞IO(NIO):用户进程发起一个IO操作以后,可做其它事情,但用户进程需要经常询问IO操作是否完成,这样造成不必要的CPU资源浪费;
异步非阻塞IO(AIO):用户进程发起一个IO操作然后,立即返回,等IO操作真正的完成以后,应用程序会得到IO操作完成的通知。类比Future模式。

NIO相对于BIO来说一大进步。客户端和服务器之间通过Channel通信。NIO可以在Channel进行读写操作。这些Channel都会被注册在Selector多路复用器上。Selector通过一个线程不停的轮询这些Channel。找出已经准备就绪的Channel执行IO操作。 NIO 通过一个线程轮询,实现千万个客户端的请求,这就是非阻塞NIO的特点
异步非阻塞,服务器实现模式为一个有效请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理.
AIO方式使用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用OS参与并发操作,编程比较复杂,JDK7开始支持。
AIO 并没有采用NIO的多路复用器,而是使用异步通道的概念。其read,write方法的返回类型都是Future对象。而Future模型是异步的,其核心思想是:去主函数等待时间

五种IO模型的区别

在这里插入图片描述

查询平均成绩大于等于 60 分的同学的学生编号和学生姓名和平均成绩

SELECT student.s_id, student.s_name,a.avg FROM student
INNER join 
(SELECT s_id,avg(s_score) as avg
FROM score GROUP BY s_id
HAVING avg(s_score)>=60) a
on student.s_id=a.s_id

Bird x = new Animal() 为什么这样写不好?

一般子类会对父类进行一定的扩展,如果子类引用调用父类不存在的方法或变量,就会出错;通常多态;父类引用指向不同子类实例。

进程通信的各种方式

进程间通信的方式通常分为管道、系统 IPC、套接字三种,其中管道有无名管道、命名管道,系统 IPC 有消息队列、信号、共享内存

无名管道的本质是在内核缓冲区的环形队列,每次读取数据后缓冲区都会移动,并且无名管道只能在有亲缘关系的进程间使用
命名管道则以文件的形式存在,由于有一个路径名,使用没有亲缘关系的进程间也可以使用命名管道
消息队列是存放在内核中的消息链表,具有特定的格式,支持多种数据类型,且允许多个进程进行读写
信号是软件层次上对中断机制的一种模拟,是一种异步通信方式,并且信号可以在用户空间进程和内核之间直接交互
共享内存顾名思义就是两个进行对同一块内存进行读写,是最快的 IPC 形式,但不适合大量的数据传输
Socket 是对 TCP/IP 协议族的封装,不仅可以用于本机上的进程间通信,更多的被用于网络通信中

进程调度算法

  • 先来先服务调度算法
    对长作业比较有利,但对短作业不利
  • 时间片轮转调度法
    每个进程只能运行一个时间片
    时间片的大小对系统性能的影响很大,时间片过大就和先来先服务算法一样,时间片过小会导致进行切换开销大
  • 短作业优先调度算法
    对长作业不利,不能保证紧迫性作业(进程)被及时处理
  • 最短剩余时间优先
    允许抢占,总是选择预期剩余时间最短的进程
    高响应比优先调度算法
    R=(w+s)/s (R 为响应比,w 为等待处理的时间,s 为预计的服务时间),选择 R 最大的进行执行
  • 优先级调度算法
    进程优先级可以分为静态优先级和动态优先级
  • 多级反馈队列调度算法
    分为多个队列,每个队列中按时间片轮转调度算法来进行进程调度,每一级的队列时间片大小也不一样,如果进行在第一个队列的时间片内没有完成,就会进入第二个队列,以此类推,只有当第一个队列为空才执行第二个队列的进行。短作业有限且长作业不会太长时间不被处理

线程上下文加载器(非双亲委派模式)

java默认类加载器是双亲委派。但是在一些应用场景不是非常适合。比如java提供的服务接口SPI,常见的SPI有JDBC、JBI等。jdbc为例,由二部分组成,java类库提供的接口和数据库厂商提供的具体实现类。首先spi接口是java核心类库的一部分,所以是由java启动类加载器来加载,但是spi的具体实现类只能由应用类加载器来加载,显然启动类是没法找到SPI的实现类。因为启动类是最顶级的类加载器,他没法代理给应用程序类加载器。所以在这种情况 双亲委派模式就不是特别合适。

消息队列问题

如何解决丢数据的问题
transaction机制就是说,发送消息前,开启事物(channel.txSelect()),然后发送消息,如果发送过程中出现什么异常,事物就会回滚(channel.txRollback()),如果发送成功则提交事物(channel.txCommit())。
然而缺点就是吞吐量下降了。因此,按照博主的经验,生产上用confirm模式的居多。一旦channel进入confirm模式,所有在该信道上面发布的消息都将会被指派一个唯一的ID(从1开始),一旦消息被投递到所有匹配的队列之后,rabbitMQ就会发送一个Ack给生产者(包含消息的唯一ID),这就使得生产者知道消息已经正确到达目的队列了.如果rabiitMQ没能处理该消息,则会发送一个Nack消息给你,你可以进行重试操作
消息队列丢数据
处理消息队列丢数据的情况,一般是开启持久化磁盘的配置。这个持久化配置可以和confirm机制配合使用,你可以在消息持久化磁盘后,再给生产者发送一个Ack信号。这样,如果消息持久化磁盘之前,rabbitMQ阵亡了,那么生产者收不到Ack信号,生产者会自动重发

排查内存泄漏

1 确定频繁Full GC现象:通过“虚拟机进程状况工具:jps”找出正在运行的虚拟机进程id,再利用“虚拟机统计信息监视工具:jstat”监视虚拟机各种运行状态信息,发现fullGC频繁,确认内存泄露
2 找出导致频繁Full GC的原因:使用“Java内存影像工具:jmap”生成堆转储快照;使用Java heap分析工具(如MAT),找出内存占用超出预期的嫌疑对象
3.根据情况,分析嫌疑对象和其他对象的引用关系。
4.分析程序的源代码,找出嫌疑对象数量过多的原因

ContextLoaderListener作用

ContextLoaderListener的作用就是启动Web容器时,读取在contextConfigLocation中定义的xml文件,自动装配ApplicationContext的配置信息,并产生WebApplicationContext对象,然后将这个对象放置在ServletContext的属性里,这样我们只要得到Servlet就可以得到WebApplicationContext对象,并利用这个对象访问spring容器管理的bean。
简单来说,就是上面这段配置为项目提供了spring支持,初始化了Ioc容器

java线程生命周期

在这里插入图片描述

java BIO NIO AIO

同步阻塞IO(BIO):用户进程发起一个IO操作以后,必须等待IO操作的真正完成后,才能继续运行;
同步非阻塞IO(NIO):用户进程发起一个IO操作以后,可做其它事情,但用户进程需要经常询问IO操作是否完成,这样造成不必要的CPU资源浪费;
异步非阻塞IO(AIO):用户进程发起一个IO操作然后,立即返回,等IO操作真正的完成以后,应用程序会得到IO操作完成的通知。类比Future模式。
NIO相对于BIO来说一大进步。客户端和服务器之间通过Channel通信。NIO可以在Channel进行读写操作。这些Channel都会被注册在Selector多路复用器上。Selector通过一个线程不停的轮询这些Channel。找出已经准备就绪的Channel执行IO操作。 NIO 通过一个线程轮询,实现千万个客户端的请求,这就是非阻塞NIO的特点
异步非阻塞,服务器实现模式为一个有效请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理.
AIO方式使用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用OS参与并发操作,编程比较复杂,JDK7开始支持。
AIO 并没有采用NIO的多路复用器,而是使用异步通道的概念。其read,write方法的返回类型都是Future对象。而Future模型是异步的,其核心思想是:去主函数等待时间

volatile 原理

原理是内存屏障(memory barrier)当cpu写数据时,如果发现一个变量在其他cpu有复本,发出信号通知其他cpu上的复本对应的缓存设置为无效状态,当其他cpu读取变量复本,发现该缓存行是无效的,然后会重新从主存中读取。

ThreadLocal应用

比如依赖主线程的特定参数arg,来完成后续任务。如果有多个线程,那么每个线程都需要传递该参数,代码冗余。
使用ThreadLocal。定义该参数arg;
参数无需再次传递,直接在每个线程使用。对每个线程来说值是唯一的。

java异常

非正常异常(Error):这类异常的命名以 Error 结尾,比如 OutOfMemoryError,NoSuchMethodError。这类异常,编译器编译时不检查,应用程序不需要处理,接口不需要声明,接口规范也不需要纪录;

运行时异常(RuntimeException):这类异常的命名通常以 Exception 结尾,比如 IllegalArgumentException,NullPointerException。这类异常,编译器编译时不检查,接口不需要声明,但是应用程序可能需要处理,因此接口规范需要记录清楚;

非运行时异常:除了运行时异常之外的其他的正常异常都是非运行时异常,比如 InterruptedException,GeneralSecurityException。和运行时异常一样,命名通常以 Exception 结尾。这类异常,编译器编译时会检查异常是否已经处理或者可以抛出,接口需要声明,应用程序需要处理,接口规范需要记录清楚。

通常如果一个方法是重写方法,一定要使用 Override 注解,清楚地标明这个方法是重写的方法。 使用 Override 注解的另一个好处是,如果父类更改了方法,子类的编译就会出错。这样我们就能在第一时间获得通知,既可以及时地变更子类,也可以使父类的变更更加合理。

java终止线程的四种方式

  • 正常运行结束
  • 使用退出标识符。然后使用while条件判断
  • 使用interrupt
  • stop(不安全)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值