JAVA面试题

1.java单例模式

java单例模式主要作用于频繁的调用,而不需要创建实体类的情况下,如工具类的使用,数据库的操作

单例模式需要将构造方法设为私有,防止被调用

饿汉模式

饿汉模式初始化创建了对象,每次调用不会创建对象(因为私有的),每次调用都会返回一个对象,所以说饿汉模式是线程安全的

懒汉模式与饿汉模式模式的区别就是:懒汉模式在初始化不创建对象,而是先判断,如果没有对象就会被创建,也就是说,每次判断的时候,这个对象就会创建一个,这样在多线程中懒汉模式是不安全的,既然懒汉模式存在安全问题,但是还是有人会用,解决线程不安全的问题是线程加锁

2.线程相关

(1)线程创建方式,线程安全

在语言层面有两种方式。java.lang.thread类的实例就是一个线程,但是它需要调用java.lang.Runnable接口来执行,由于多线程本身就是调用Runnable接口,所以继承java.lang.thread类或者直接调用Runnable接口来调用run()方法实现线程

如果你的代码所在的进程中有多个线程同时运行,而这些可能同时运行一段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他变量的值也和预期的是一样的,就是线程安全的。一个线程安全的计数器的同一个实例对象在被多个线程使用的情况下也不会出现计算失误。很显然你可以将集合分成两方面,线程安全和非安全。Vector是用同步方法来实现线程安全的。而他和相似的ArrayList不是线程安全的。

(2)本地线程:ThreadLocal

ThreadLocal是java里一个特殊的变量。每个线程都有一个ThreadLocal,就是每个线程都拥有了自己独立的一个变量,竞争条件被彻底消除了。它是为创建代价高昂的对象获取线程安全的好方法,比如你可以用ThreadLocal让SimpleDateFormat变成线程安全的,因为那个类创建代价高昂且每次调用都需要创建不同的实例所以不值得在局部范围使用它,如果为每个线程提供一个自己独有的变量拷贝,将大大提高效率。首先,通过复用减少了代价高昂的对象的创建个数。再次,你有没有使用高价的同步或者不变性的情况下获得了线程安全。线程局部变量的另一个不错的例子是ThreadLocalRandom类,它是多线程环境中减少了创建代价高昂的Random对象的个数

3.sql,mysql

事务隔离级别

(1)Read Uncomitted(读取未提交内容)

在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少。读取未提交的数据,也被称之为脏读(Dirty Read)。

(2)Read Committed(读取提交内容)

 这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。这种隔离级别也支持所谓的不可重复读(Nonrepeatable Read),因为同一事务的其他实例在该实例处理其间可能会有新的commit,所以同一select可能返回不同结果。

(3)Repeatable Read(可重读)

这是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。不过理论上,这会导致另一个棘手的问题:幻读(Phantom Read)。简单的说,幻读指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影”行。InnoDB和Falcon存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决了该问题。

(4)Serializable(可串行化)

这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。

 

隔离级别

读数据一致性

脏读

不可重复读

幻读

未提交读(Read uncommitted)

最低级别,只能保证不读取物理上损坏的数据

已提交读(Read committed)

语句级

可重复读(Repeatable read)

事务级

可序列化(Serializable)

最高级别,事务级

leftjion和fulljoin的区别,union和unionall的区别

left join(左连接)返回包括左表中的所有记录和右表中联结字段相等的记录

right join(右连接)返回包括右表中的所有记录和左表中联结字段项的纪录

inner join(等值连接)只返回两个表中连接字段相等的行

Union:对两个结果集进行并集操作,不包括重复行,同时进行默认规则的排序; 

Union All:对两个结果集进行并集操作,包括重复行,不进行排序; 

in后面可以最多跟几个字段

in条件后面有多个字段,in后面只能有一个字段

4. maven、grade

maven现在已经是行业标准,grade是后起之秀,很多人对他的了解都是从Android studio中得到的,grade抛弃了maven的基于xml的繁琐配置,众所周知xml的阅读体验比较差,对于机器来说虽然容易识别,但毕竟是由人去维护的。取而代之的是grade采用了领域特定语言Groovy的配置,大大简化了构建

5.什么是nosql,he关系型数据库的区别

Nosql(nosql=not only sql)指的是菲关系型的数据库

实质:非关系型数据库的实质:非关系型数据库产品是传统关系型数据库的功能阉割版本,通过减少用不到或很少用的功能,来大幅度提高产品性能

价格:目前基本大部分主流的非关系型数据库都是免费的。而比较有名气关系型数据库都是免费了。而比较有名气的关系型数据库,比如Oracle,DB2,MSSOL是收费的。虽然mysql免费,但是它需要很多工作才能正式用于生产

功能:实力开发中,有很多业务需求,其实并不需要完整的关系型数据库功能,非关系型数据库的功能就足够用了。这种情况下,使用性能更高、成本更低的非关系型数据库当然是更明智的选择

传统sql数据可有3个缺点

许可费用昂贵、不能自动Sharding、严格的Schema

互联网公司一般都是技术密集型的,就自己根据自己的需求搞了一套数据存储,牺牲了严格一致性,满足互联网伸缩性的要求。

nosql 当年是为了处理 杂乱的非结构化数据来设计的 比如 网页访问信息 那就如楼上说的 阉割了sql 的 acid 特性 这样当然快了啊 比如插入数据 

相反如果是一些 交易数据 数据的安全稳定 压倒一切的时候 rdbms 就显现威力了 但是rdbms 在面对nosql的 一些挑战之后 大力优化了 对于一些 非结构化数据的支持 比如json 数据 同时rdbms 对于 olap and oltp 的支持 也要比 nosql快的你是一点半点

非关系型数据库的优势:1. 性能NOSQL是基于键值对的,可以想象成表中的主键和值的对应关系,而且不需要经过SQL层的解析,所以性能非常高。2. 可扩展性同样也是因为基于键值对,数据之间没有耦合性,所以非常容易水平扩展。

关系型数据库的优势:1. 复杂查询可以用SQL语句方便的在一个表以及多个表之间做非常复杂的数据查询。2. 事务支持使得对于安全性能很高的数据访问要求得以实现。对于这两类数据库,对方的优势就是自己的弱势,反之亦然。

6.非惯性数据库Redis和MongoDB的区别

MongoDB更类似于mysql,支持字段索引,游标操作,其优势在于查询功能比较强大,擅长查询JSON数据,能存储海量数据,但是不支持事务

mysql在大数据量时效率显著下降,MongoDB更多时候作为关系数据可的一种替代

Redis数据去不存在内存,定期写入磁盘,当内存不够时,可选择指定的LRU算法删除数据

MongoDB数据存在内存,右linux系统map实现,当内存不够时,只将热点数据放入内存,其他数据存在磁盘

Redis支持的数据结构丰富,包括hash、set、list等。

MongoDB数据结构比较单一,但是支持丰富的数据表达,索引,最类似关系型数据库,支持的查询语言非常丰富。

二者性能都比较高,应该说都不会是瓶颈。二者均支持持久化。

 MongoDB集群技术比较成熟,Redis从3.0开始支持集群。

7.Redis的使用

Redis是一个开源的使用ANSI C语言编写、遵守BSD协议、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供 多  种语言的API。
它通常被称为数据结构服务器,因为值(value)可以是 字符串(String), 哈希(Map), 列表(list), 集合(sets) 和 有序集合    (sorted sets)等类型。

8.redis基本类型

 数据类型
Redis 字符串数据类型的相关命令用于管理 redis 字符串值

Redis hash 是一个string类型的field和value的映射表,hash特别适合用于存储对象。
Redis 中每个 hash 可以存储 232 - 1 键值对(40多亿)

Redis列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素导列表的头部(左边)或者尾部(右边)

Redis的Set是string类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。
Redis 中 集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。
集合中最大的成员数为 232 - 1 (4294967295, 每个集合可存储40多亿个成员)
一个列表最多可以包含 232 - 1 个元素 (4294967295, 每个列表超过40亿个元素)

Redis 有序集合和集合一样也是string类型元素的集合,且不允许重复的成员。
   不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。
   有序集合的成员是唯一的,但分数(score)却可以重复。
   集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。 集合中最大的成员数为 232 - 1 (4294967295, 每个集合可存储40多亿个成员)。

Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。
   Redis 客户端可以订阅任意数量的频道。

9. memcache和redis对比

 Redis和Memcache都是将数据存放在内存中,都是内存数据库。不过memcache还可用于缓存其他东西,例如图片、视频等等。

数据类型--Memcache在添加数据时就要指定数据的字节长度

虚拟内存--Redis当物理内存用完时,可以将一些很久没用到的value 交换到磁盘

过期策略--memcache在set时就指定,例如set key1 0 0 8,即永不过期。Redis可以通过例如expire 设定

分布式--设定memcache集群,利用magent做一主多从;redis可以做一主多从。都可以一主一从

存储数据安全--memcache挂掉后,数据没了;redis可以定期保存到磁盘(持久化)

灾难恢复--memcache挂掉后,数据不可恢复; redis数据丢失后可以通过aof恢复

  1. 熟悉JVM,包括内存模型、类加载机制以及性能优化

 

Java虚拟机主要分为一下几个区

①方法区:

有时候也成为永久代,在该区内很少发生垃圾回收,但是并不代表不发生GC,在这里进行的GC主要是对方法区里的常量池和对类型的卸载
2. 方法区主要用来存储已被虚拟机加载的类的信息、常量、静态变量和即时编译器编译后的代码等数据。
3. 该区域是被线程共享的。
4. 方法区里有一个运行时常量池,用于存放静态编译产生的字面量和符号引用。该常量池具有动态性,也就是说常量并不一定是编译时确定,运行时生成的常量也会存在这个常量池中

②虚拟机栈:
1. 虚拟机栈也就是我们平常所称的栈内存,它为java方法服务,每个方法在执行的时候都会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接和方法出口等信息。
2. 虚拟机栈是线程私有的,它的生命周期与线程相同。
3. 局部变量表里存储的是基本数据类型、returnAddress类型(指向一条字节码指令的地址)和对象引用,这个对象引用有可能是指向对象起始地址的一个指针,也有可能是代表对象的句柄或者与对象相关联的位置。局部变量所需的内存空间在编译器间确定
4.操作数栈的作用主要用来存储运算结果以及运算的操作数,它不同于局部变量表通过索引来访问,而是压栈和出栈的方式
5.每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程中的动态连接.动态链接就是将常量池中的符号引用在运行期转化为直接引用。

③本地方法栈
本地方法栈和虚拟机栈类似,只不过本地方法栈为Native方法服务。

④堆
java堆是所有线程所共享的一块内存,在虚拟机启动时创建,几乎所有的对象实例都在这里创建,因此该区域经常发生垃圾回收操作。

⑤程序计数器
内存空间小,字节码解释器工作时通过改变这个计数值可以选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理和线程恢复等功能都需要依赖这个计数器完成。该内存区域是唯一一个java虚拟机规范没有规定任何OOM情况的区域

 

 

内存:

Java内存模型(JVM)是线程间通信的控制机制,JVM定义了主内存和线程之间抽象关系。线程之间的共享变量存储在主内存(main memony)中,每个线程都有一个私有的内存地址(local menmory),本地内存中存储了该线程以读/写共享变量的副本。本地内存是JVM的一个抽象概念,并不真实存在。它涵盖了缓冲,写缓冲区,寄存器以及其他的硬件和编译器优化

java类加载过程?

Java类加载需要经历7个过程

加载

加载时类加载的第一个过程,在这个阶段,将完成三件事情:

  1. 通过一个类的全限定名获取该类的二进制流
  2. 将二进制流中的静态存储结构转化为方法去运行时数据结构
  3. 在内存中生成该类的class对象,作为该类的数据访问入口。

验证:

验证的目的是为了确保class文件的字节流中的信息不会危害到虚拟机。在该阶段主要完成以下四中验证:

  1. 文件格式验证:验证字节流是否符合class文件的规范,如主次版本是否在当前虚拟机范围内,常量池中的常量是否有不被支持的类型
  2. 元数据验证:对字节码描述的信息进行语义分析,如这个类是否有分类,是否继承了不被继承的类等。
  3. 字节码验证:使整个过程中最复杂的一个阶段,通过验证数据流和控制流的分析,确保程序语义是否正确,主要针对方法体的验证。如:方法中的类型是否正确,跳转指令是否正确等
  4. 符号引用验证:这个动作在后面的解析过程发生,主要是为了确保解析动作能正常执行

准备

准备阶段是为类的静态变量分配内存并将其初始化默认值,这些内存都将在方法区进行分配。准备阶段不分配类中的实例变量的内存,实例变量将会在对象实例化时随着对象一起分配在java堆中。

如:public static int a =123;//准备阶段a初始值为0.在初始化阶段才会变为123.

10.简述java类加载机制

虚拟机把描述类的数据从class文件加载到内存,并对数据进行校验,解析和初始化,最终形成可以被虚拟机直接使用的java类型

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

double_lifly

点喜欢就是最好的打赏!!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值