1、HashMap
根据键进行存储数据,快速访问遍历,取得数据完全随机。不支持线程同步。同一时刻可以有多个线程同时写HashMap,可能导致数据不一致。如果需要同步,可以使用Collections的synchronizedMap方法使HashMap具有同步的能力,或者使用ConcurrentHashMap。
2、Volatile
保证有序性和可见性。编译器和CPU会做重排序,重排序是为了减少流水线的阻塞(数据相关性),引起流水阻塞,提高CPU的执行率。happens-befor规则,有序实现插入。可见性:java内存分为主内存和工作内存,加上volatile关键字,可以使得数据前后是同步的。MESI是保证多核之间数据不一致性。
3)若类不能重写,eques()方法就是比较对象地址。
3、Hibernate中的Query接口
String hql = "from User where age > ?";
Query query = session.createQuery(hql);
query.setInteger(0, 25);
List<User> list = query.list();
其中的方法:
list()方法,无法利用一级缓存和二级缓存,对于缓存只写不读,只能开启查询缓存的前提下使用查询缓存;iterate()方法充分利用缓存,如果目标数据只读或者读取频繁,使用iterate()方法可以减少性能开销。
list()不会引起N+1问题,而iterate()方法可能引起N+1查询问题。(
- 1+n是执行一次查询获取n条主数据后,由于关联引起的执行n次查询从数据;它带来了性能问题;
- 一般来说,通过懒加载 可以部分缓解1+n带来的性能问题)
5 、类加载
Class.forName(..)与ClassLoader.loadClass(..)进行类装载的过程。
(1)Class.forName(className) 在执行该方法时,其实该方法内部调用的是它的一个重载方法:forName(className,boolean,ClassLoader)
该重载方法共有三个参数,其中,第一个参数是类的包路径,第二个是一个布尔值,默认为true;表示在类加载时会进行初始化。第三个参数指一个类加载器,默认使用的就是当前类使用的类加载器。
(2)ClassLoader.loadClass(className) 在执行该方法时,其实该方法内部也是调用一个重载方法:loadClass(className,boolean)
该重载方法共有两个参数,其中,第一个参数是类的包路径,第二个是一个布尔值,默认是false;表示类加载时不会链接,同样也不进行初始化。
综上所述,可知Class.forName(..)与ClassLoader.loadClass(..)的主要区别是:
Class.forName得到的class是已经初始化完成的,该方法适合那些在类加载时需要初始化一些东西的情况。比如,加载数据库驱动。
Classloder.loaderClass得到的class是还没有链接的,该方法适合在类加载时不需要一些初始化的情况。
6 、Object的基本方法
hashCode();返回对象的哈希值,可以用来提高Map里面的搜索晓丽,Map会根据不同的hashCode()来放不同位置,Map搜索也是通过hashCode()来找,然后根据eques()方法判断这个位置对象与当前要插入的对象是否为同一个对象。
equals(Object);
1、如果两个对象相同,则hashCode一定相同;
2、如果对象hashCode()相同,它并不一定相同,就是eques()更强一些。
toString();
7、什么是内存泄漏以及检测和处理方式
内存泄漏其实就是创建新对象的适合,无法从Heap中获取足够的内存分配给对象,这样会导致泄漏,而出现泄漏主要是不断往容器里面存放对象,但是容器没有相应的大小限制或者清除机制,容易出现内存泄漏。
1)内存泄漏的表现:OutOfMemoryError.
2)内存泄漏引起的原因:
A、静态集合类引起内存泄漏;HashMap、Vector等使用容易出现内存泄漏,静态变量周期和应用程序一致的对象Object也不能被释放,因为一直被Vector等引用。
B、集合里面对象属性被修改后,再调用remove()方法时不起作用;
C、监听器:适当的使用监听器,例如addXXXListener()等方法来增加监听器,但往往再释放对象的时间记得删除这些监听器,从而增加了内存泄漏的机会。
D、各种连接
例如,数据库连接(dataSourse.getConnection()),网络连接(scoket)和io连接,需要调用close()进行连接关闭,否则不会自动被GC回收的。对于Resultset 和Statement 对象可以不进行显式回收,但Connection 一定要显式回收,因为Connection 在任何时候都无法自动回收,而Connection一旦回收,Resultset 和Statement 对象就会立即为NULL。
E、内部类和外部模块的引用
F、单例模式
不正确的单例模式会引起内存泄漏,
3)解决办法1:继续监听GC的活动,时间增加之后,内存是否会增加,如果有,一定存在内存泄漏;
4)任何发现内存泄漏:
1. jstat -gc pid
可以显示gc的信息,查看gc的次数,及时间。
其中最后五项,分别是young gc的次数,young gc的时间,full gc的次数,full gc的时间,gc的总时间。
2.jstat -gccapacity pid
可以显示,VM内存中三代(young,old,perm)对象的使用和占用大小,
如:PGCMN显示的是最小perm的内存使用量,PGCMX显示的是perm的内存最大使用量,
PGC是当前新生成的perm内存占用量,PC是但前perm内存占用量。
其他的可以根据这个类推, OC是old内纯的占用量。
3.jstat -gcutil pid
统计gc信息统计。
4.jstat -gcnew pid
年轻代对象的信息。
5.jstat -gcnewcapacity pid
年轻代对象的信息及其占用量。
6.jstat -gcold pid
old代对象的信息。
7.stat -gcoldcapacity pid
old代对象的信息及其占用量。
8、红黑树与AVL的区别
1)平衡二叉树(AVL树)
平衡二叉树AVL,特殊二叉排序,左右子树都是平衡二叉树,且左右子树高度之差的绝对值不超过1.以树种所有节点为根的树的左右子树高度之差的绝对值不超过1;
2 )红黑树
红黑树是一种二叉查找树,但每个节点增加一个存储位表示节点的颜色,可以是 红或黑。红黑树确定没有一条路径会比其他路径长出两倍。
性质:
每个节点非红即黑;
根节点是黑的;每个叶节点都是黑的;对于任意节点而言,其到叶子节点树null指针的每条都包含相同数目的黑节点;
区别:
AVL树的高度平衡,频繁的插入和删除会引发rebalance,导致效率下降,红黑树不是高度平衡;
9、int范围-2^31-2^31-1
10、反射机制
反射机制指的是程序在运行时能够获取自身的信息,在java只要给定类的名字,那么久可以通过反射机制来获得类的所有信息。
那里用到反射机制,Class.forName("com.mysql.jdbc.Driver.class").newInstance();
1)反射机制的优点和缺点
动态编译:运行时确定类型,绑定对象,动态编译最大限度发挥java的灵活性,体现了多态的应用,有以降低类之间的耦合性;
静态编译:在编译时确定类型,绑定对象,即通过;
Class c=Class.forName("className");注明:className必须为全名,也就是得包含包名,比如,cn.netjava.pojo.UserInfo;
Object obj=c.newInstance();//创建对象的实例
2)反射机制可以做什么
有了java反射机制,指需要些一个dao类,四个方法,增删改查,传入不同对象,久可以实现数据库的访问,增删改查操作。
反射机制帮我们做那些重复的有规则的事情,所以现在很多自动生成的代码都是运用反射机制实现的。
反射机制的应用实例:https://www.cnblogs.com/wglIT/p/7590468.html
11、java强引用和弱引用
Java执行GC判断对象是否存活有两种方式其中一个就是引用计数。
JDK1.2版本开始,对象的引用被分为四个级别,从而使得程序更加灵活的控制对象的生命周期,这四个级别依次时:强引用、软引用、弱引用和虚引用。
1)强引用
强引用是最普遍的引用,垃圾回收器绝不会回收它,
Object strongReference = new Object();
当内存空间不足时,java虚拟机宁愿抛出OutOfMemoryError错误,使得程序停止,也不愿意随意回收强引用对象。。如果强引用对象不适用时,需要弱化从而使得GC能够回收;
strongReference = null;
显示设置strongReference对象为null,或者超出对象的生命周期范围,则gc认为该对象不存在引用,这时可以回收这个对象。
public void test() {
Object strongReference = new Object();
// 省略其他操作
}
在方法内部有一个强引用,这个引用保存java栈种,而真正的引用内容Object保存在java堆中;
方法运行完会退出方法栈,则引用对象的引用数为0,这个对象就会被回收。
如果时全局变量,久不需要这个对象赋值null,因为强引用不会被回收。
2)软引用softReference
如果一个对象只具,则内存空间充足时,垃圾回收器就不会回收它,如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。
软引用可来实现内存敏感的高速缓存。
// 强引用
String strongReference = new String("abc");
// 软引用
String str = new String("abc");
SoftReference<String> softReference = new SoftReference<String>(str);
软引用可以和一个引用队列联合起来使用,如果软引用所引用对象被垃圾回收,虚拟机就会把这个软引用加入到与之关联的引用队列中。
内存不足,软引用的引用对象会置为null,然后就通知垃圾回收器进行回收。
垃圾回收线程会在虚拟机抛出OutOfMemoryError之前回收软引用对象,而且虚拟机优先回收长期闲置的软引用对象,较新的则可能暴露,引入引用队列ReferenceQueue。
应用场景:
浏览器按钮的回退,显示的内容时从缓存中取出来的。
- 如果一个网页在浏览结束时就进行内容的回收,则按后退查看前面浏览过的页面时,需要重新构建;
- 如果将浏览过的网页存储到内存中会造成内存的大量浪费,甚至会造成内存溢出。
3)弱引用
生命周期更短暂,发现弱引用就直接进行回收。不过垃圾回收器是一个优先级很低的线程,因此不一定被很快的发现。
12、CPU时间片轮转
分时系统中采用时间片轮转算法进行进程得调度。时间片是指一个较小得时间间隔约为10ms~100ms。简单时间片轮转算法中,系统将所有就绪进程按照FIFO规则排成一个队列,将cpu分配给队首进程,且规定它最多只能连续执行一个时间片,若时间片用完时进程未完成,也必须将其插入就绪队列末尾,并把cpu交给下一个进程。
时间片轮转法只用于进程调度,属于抢占调度方式,特点时简单易行不、平均相应时间短,利于处理紧急任务。
1)cpu切片:
2)单核cpu就是相当于阻塞程序,工作期间只能执行某个程序;
3)多核cpu由多个cpu组成,可以通过内部总线来交互数据,共享数据。每个核都有自己得寄存器,alu运算单元等。但是一级二级缓存是共享得,这些cpu通过总线来交互数据,并且工作并行,资源分配由操作系统完成
4)cpu时间切片
cpu steal time
如果当前虚拟机得steal time超过了设置得阈值,会关闭这台虚拟机并且在另外一台物理机上面重启。
虚拟机与虚拟环境得宿主机上的多个虚拟机实例共享物理资源,其中cpu时间切片,如果你的虚拟机的物理机虚拟比是1/4,cpu使用率不会限制。
5)用户态和系统态
A、用户态:执行状态简称用户态;只受限的访问内存,且不允许访问外围设白,占用cpu的能力被剥夺,cpu资源可以被其他程序获取。
B、系统态:就是系统执行的状态;cpu可以访问内存的所有数据,包括外围设备,硬盘、网卡,cpu也可以将自己从一个程序切换到另一个程序。
进程的用户程序段在执行时,该进程属于用户态,而一个进程的系统程序段在执行时,处于系统态;
C、为什么用户态和内核态:
主要为了把用户程序和系统程序区分开,以利于程序的共享和保护。也就是相应限制不同程序直接的访问能力,防止获取别的程序的内存数据,或者获取外围设备的数据,并发送到网络,cpu划分出两个权限等级-用户态和内核态;
所有程序都是运行在用户态的,但有时候程序需要内核的事情,例如从磁盘读取数据,或者从键盘获取输入等。而唯一可以做这些事情的就是操作系统,所以程序就需要先操作系统以程序的名义来执行这些操作。
1)用户态程序将一些数据值放在寄存器中,或者使用参数创建堆栈stack frame,依次表明需要操作系统提供的服务;
2)用户态程序执行陷阱质量
3)cpu切换到内核态,并跳到位于内存指定位置的指令,这些指令时操作系统的一部分,他们具有内存保护,不可被用户态程序访问;
4)这些指令称之为陷阱trap或者系统调用处理器system call handler。他们会读取程序存放入内存的数据参数,并执行程序请求的服务;
5)系统调用完成,操作系统会重置cpu未用户态,并返回系统调用结果。
6)用户态切换到内核态的3种方式
a、系统调用:用户态进程申请使用操作系统提供的服务程序完成工作,而系统调用的机制核心是使用操作系统未用户特别开发的中断来实现;
b、异常:cpu执行用户态,发送异常,可以触发进入处理此异常的内核相关程序种,也就转到内核态,比如缺页异常;
c、外围设备的中断:外围设备完成用户请求的操作,会向cpu发出相应的中断信号,这是cpu会暂停执行吓一跳即将执行的指令转而执行与中断信号对应的处理程序。如果先前执行的指令是用户态,就会转为内核态,如硬盘读写操作完成。
13、数据库的左右连接
1)左连接:返回包括左表中的所有记录和右边中连接字段相等的记录;(以左表为基准,左边有数据,右边没有,则显示查询的左表所有结果,右边显示无。左边无数据,右边无论有没有数据,均为无查询结果)
2)右连接:返回包括右表中的所有记录和左表中连接字段相等的记录;
3)等值连接或者内链接,只返回两个表中连接字段相等的行;(查询两个表都有的部分)
4)全外连接:返回左右表中所有的记录和左右表中连接字段相等的记录;(两个表所有的内容均可查询出来,mysql不支持,用union来实现)
- select student.*,teacher.* from student LEFT JOIN teacher ON student.id = teacher.id
- UNION
- select student.*,teacher.* from student RIGHT JOIN teacher ON student.id = teacher.id;
14、IO方式有哪些
1)传统IO为基于流模型实现,如File抽象、输入输出流等。交互方式是同步、阻塞。读写会使得线程一直阻塞,他们之间调用时可靠的线性顺序。效率和扩展性存在局限。
2)NIO框架
java1.4引入的,提供Channel、Selector、Buffer等抽象,实现多路复用、同步非阻塞IO程序,同时提供了更接近操作系统底层的高性能数据操作方式;
1.Java NIO 概览
首先,熟悉一下 NIO 的主要组成部分:
-
Buffer,高效的数据容器,除了布尔类型,所有原始数据类型都有相应的 Buffer 实现。
-
Channel,类似在 Linux 之类操作系统上看到的文件描述符,是 NIO 中被用来支持批量式 IO 操作的一种抽象。
File 或者 Socket,通常被认为是比较高层次的抽象,而 Channel 则是更加操作系统底层的一种抽象,这也使得 NIO 得以充分利用现代操作系统底层机制,获得特定场景的性能优化,例如,DMA(Direct Memory Access)等。不同层次的抽象是相互关联的,我们可以通过 Socket 获取 Channel,反之亦然。
-
Selector,是 NIO 实现多路复用的基础,它提供了一种高效的机制,可以检测到注册在 Selector 上的多个 Channel 中,是否有 Channel 处于就绪状态,进而实现了单线程对多 Channel 的高效管理。
Selector 同样是基于底层操作系统机制,不同模式、不同版本都存在区别,例如,在最新的代码库里,相关实现如下:
Linux 上依赖于 epoll(http://hg.openjdk.java.net/jdk/jdk/file/d8327f838b88/src/java.base/linux/classes/sun/nio/ch/EPollSelectorImpl.java)。
Windows 上 NIO2(AIO)模式则是依赖于 iocp(http://hg.openjdk.java.net/jdk/jdk/file/d8327f838b88/src/java.base/windows/classes/sun/nio/ch/Iocp.java)。
-
Chartset,提供 Unicode 字符串定义,NIO 也提供了相应的编解码器等,例如,通过下面的方式进行字符串到 ByteBuffer 的转换:
3)NIO2引入异步非阻塞IO方式,异步IO操作基于事件和回调机制。应用操作直接返回,而不会阻塞在那里,当后台处理完成,操作系统会通知相应线程进行后续工作。
详情:https://www.cnblogs.com/xiaonantianmen/p/9130428.html