Java面试
线程池
首先要明确为什么要使用线程池,使用线程池会带来什么好处?
• 线程是稀缺资源,不能频繁的创建。
• 应当将其放入一个池子中,可以给其他任务进行复用。
• 解耦作用,线程的创建于执行完全分开,方便维护。
线程池是一种多线程处理形式,处理过程中将任务提交到线程池,任务的执行交由线程池来管理。
如果每个请求都创建一个线程去处理,那么服务器的资源很快就会被耗尽,使用线程池可以减少创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。
抽象类与接口区别
1.抽象类可以有构造方法,接口中不能有构造方法。
2.抽象类中可以有普通成员变量,接口中没有普通成员变量!!!!!!!(注意重点在 普通 即 非静态 和 变量!!!!)
3.抽象类中可以包含非抽象的普通方法,接口中的所有方法必须都是抽象的,不能有非抽象的普通方法。
悲观锁和乐观锁使用场景
乐观锁是在应用层加锁,而悲观锁是在数据库层加锁(for update)
乐观锁顾名思义就是在操作时很乐观,这数据只有我在用,我先尽管用,最后发现不行时就回滚。
悲观锁在操作时很悲观,生怕数据被其他人更新掉,我就先将其先锁住,让别人用不了,我操作完成后再释放掉。
悲观锁需要数据库级别上的的实现,程序中是做不到的,如果在长事务环境中,数据会一直被锁住,导致并发性能大大地降低。
一般来说如果并发量很高的话,建议使用悲观锁,否则的话就使用乐观锁。
如果并发量很高时使用乐观锁的话,会导致很多的并发事务回滚、操作失败。
总之,冲突几率大用悲观,小就用乐观。
乐观锁不会发生并发抢占资源
在多用户环境中,在同一时间可能会有多个用户更新相同的记录,这会产生冲突。这就是著名的并发性问题。
1.悲观锁:指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度,因此,在整个数据处理过程中,将数据处于锁定状态
2.乐观锁:假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。乐观锁不能解决脏读的问题。
线程安全就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。
线程不安全就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据。
死锁和脏数据就是典型的线程安全问题。
简单来说,线程安全就是: 在多线程环境中,能永远保证程序的正确性。
只有存在共享数据时才需要考虑线程安全问题。
多线程会引出很多难以避免的问题, 如死锁,脏数据,线程管理的额外开销,等等。更大大增加了程序设计的复杂度。
在Java 8 中,如果一个桶中的元素个数超过 TREEIFY_THRESHOLD(默认是 8 ),就使用红黑树来替换链表
java内存区域:
hashmap
key value
初始化容量 1左移4位16容量 2的4次方
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
加载因子系数
1分成4等分0.25 0.25*3=0.75 在容量的3/4(0.75)的时候扩容
static final float DEFAULT_LOAD_FACTOR = 0.75f;
HashMap和Hashtable的区别
HashMap没有考虑同步,是线程不安全的;Hashtable使用了synchronized关键字,是线程安全的
前者允许null作为key,后者不允许null作为key
从ConcurrentHashMap代码中可以看出,它引入了一个“分段锁”的概念,具体可以理解为把一个大的Map拆分成N个小的HashTable,根据key.hashCode()来决定把key放到哪个HashTable中。
在ConcurrentHashMap中,就是把Map分成了N个Segment,put和get的时候,都是现根据key.hashCode()算出放到哪个Segment中,ConcurrentHashMap中默认是把segments初始化为长度为16的数组。通过把整个Map分为N个Segment(类似HashTable),可以提供相同的线程安全,但是效率提升N倍,默认提升16倍。
HashMap的底层实现
Java8之前,其底层实现是数组+链表实现,Java8使用了数组+链表+红黑树实现
ConcurrentHashMap的具体实现
1、该类包含两个静态内部类HashEntry(节点)和Segment(桶);前者用来封装映射表的键值对,后者用来充当锁的角色
List有序 可以重复 set无序不可以重复
ArrayList的初始容量10 加载因子0.5
Vector的初始容量10 加载因子1
HashSet的初始容量为16,加载因子0.75
HashMap的初始容量为16,加载因子0.75 扩容增量:原容量的1倍
数据库索引原理
索引原理必须清楚一种数据结构「平衡树」(非二叉),也就是b tree或者 b+ tree,重要的事情说三遍:“平衡树,平衡树,平衡树”。当然, 有的数据库也使用哈希桶作用索引的数据结构 , 然而, 主流的RDBMS都是把平衡树当做数据表默认的索引数据结构的。
线程和进程的区别
1、进程是一个“执行中的程序”,是系统进行资源分配和调度的一个独立单位;
2、线程是进程的一个实体,一个进程中拥有多个线程,线程之间共享地址空间和其它资源
volatile关键字
该关键字可以保证可见性不保证原子性
ThreadLocal关键字
当使用ThreadLocal维护变量时,其为每个使用该变量的线程提供独立的变量副本,所以
每一个线程都可以独立的改变自己的副本,而不影响其他线程对应的副本
线程池
java.util.concurrent.ThreadPoolExecutor类就是一个线程池。客户端调用
ThreadPoolExecutor.submit(Runnabletask)提交任务
JVM划分
1、方法区:常量、静态变量、即时编译器
2、堆内存:垃圾回收的主要场所
3、程序计数器
4、虚拟机栈(栈内存):保存局部变量、基本数据类型变量以及堆内存中某个对象的引用变量
5、本地方法栈
垃圾回收算法有哪些
1、引用计数
2、标记-清除 分两个阶段 第一阶段从引用根节点开始标记所有被引用的对象,第二阶段遍历整个堆,把未标记的对象清除。
GC经常发生的区域是堆区,堆区还可以细分为新生代、老年代、
内存溢出 内存泄露是导致内存溢出的原因之一
NIO和IO的主要区别
IO 面向流 阻塞IO
NIO 面向缓冲区 非阻塞IO 选择器 选择一个通道
双亲委派模型
(1).BootStrap ClassLoader:启动类加载器,负责加载存放在%JAVA_HOME%lib目录中的
(2).Extension ClassLoader:扩展类加载器,由sun.misc.Launcher$ExtClassLoader实现,负责加载%JAVA_HOME%libext目录中的
(3).Application ClassLoader:应用程序类加载器,由sun.misc.Launcher$AppClassLoader实现,负责加载用户类路径classpath上所指定的类库
Java8新特性
1、Lambda表达式允许我们将函数当成参数传递给某个方法
2、函数式接口@Functionallnterface来标明该接口是一个函数式接口
3、引入重复注解@Repeatable
4、接口中可以实现方法default方法
5、注解的使用场景拓宽
6、新的包java.time包
dubbo
Provider在容器里面进行启动,启动之后往服务中心进行服务一个注册,然后Consume订阅之前注册过的服务,如果服务发生改变注册中心会通知Consume,Consume拿到订阅关系之后就直接invoke调用Provider同时有个Monitor监控他们的调用情况
会员中心调用订单中心
订单需要提供一个接口给会员调用
Consumer:192.168.0-.192/com.tl.IOrderService?application=UserCp
数据库索引作用 底层数据结构 为什么使用这种结构
索引 是对数据库表中一列或多列的值进行排序的一种结构,使用索引可快速访问数据库表中的特定信息
底层数据结构B+树
使用B+树的原因:查找速度快,效率高,
聚集索引和非聚集索引根本区别
是表记录的排列顺序和与索引的排列顺序是否一致
聚集索引表记录的排列顺序和索引的排列顺序一致
非聚集索引制定了表中记录的逻辑顺序,但是记录的物理和索引不一定一致
MyISAM和InnoDB的区别
MyISAM不支持事务,InnoDB是事务类型的存储引擎
MyISAM只支持表级锁InnoDB支持行级锁和表级锁
MyISAM不支持外键InnoDB支持外键
MyISAM支持全文索引InnoDB不支持
MyISAM表不支持事务、不支持行级锁、不支持外键
InnoDB表支持事务、支持行级锁、支持外键
Spring 知识点
Spring 的 IOC 和 AOP
• IOC:控制反转,(解耦合)将对象间的依赖关系交给 Spring 容器,使用配置文件来创建所依赖的对象,由主动创建对象改为了被动方式;
• AOP:面向切面编程,将功能代码从业务逻辑代码中分离出来;
AOP 的实现方式有哪几种?如何选择?
JDK 动态代理实现和 cglib 实现
选择:
- 如果目标对象实现了接口,默认情况下会采用 JDK 的动态代理实现 AOP,也可以强制使用 cglib 实现 AOP;
- 如果目标对象没有实现接口,必须采用 cglib 库,Spring 会自动在 JDK 动态代理和 cglib 之间转换。
扩展:JDK 动态代理如何实现
JDK 动态代理,只能对实现了接口的类生成代理,而不是针对类,该目标类型实现的接口都将被代理。
原理是通过在运行期间创建一个接口的实现类来完成对目标对象的代理
Mybatis 知识点
关于 MyBatis 主要考察占位符#和 $ 的区别,区别如下:
符号将传入的数据都当做一个字符串,会对自动传入的数据加一个双引号;
- $ 符号将传入的数据直接显示生成 SQL 中;
符号存在预编译的过程,对问号赋值,防止 SQL 注入;
- $符号是直译的方式,一般用在 order by ${列名}语句中;
- 能用#号就不要用 $ 符号
Linux常用命令
文件和目录:
pwd 显示当前目录
ls 显示当前目录下的文件和目录:
- ls -F 可以区分文件和目录;
- ls -a 可以把隐藏文件和普通文件一起显示出来;
- ls -R 可以递归显示子目录中的文件和目录;
- ls -l 显示长列表
- ls -l test 过滤器,查看某个特定文件信息。可以只查看 test 文件的信息
处理文件方面的命令有:touch、cp、 In、mv、rm
处理目录方面的命令:mkdir
查看文件内容:file、cat、more、less、tail、head
eg. 找出进程名中包括 java 的所有进程:ps -ef | grep java
top 命令 实时监测进程
压缩数据
- tar -xvf 文件名
- tar -zxvf 文件名
- tar -cvzf 文件名
结束进程:kill PID 或者 kill all