红色加粗一定要仔细看!!!
JVM:
启动流程:先去装载配置,根据当前路径和系统版本寻找jvm.cfg ,然后去找需要的jvm.dll(主要实现), dll初始化jvm虚拟机,获得一些jnienv接口等,然后找到main方法并运行。
内部结构:首先会有类加载器子系统(classloader),把java文件的class文件加载的jvm中,加载到内存空间(方法区,java堆,java栈,本地方法区(native方法调用)),虚拟机运行的时候和普通的cpu一样,需要一个指针指向下一条指令地址,就是pc寄存器。有一个执行引擎来执行虚拟机代码,就是class类的字解码。运行的时候还有一个垃圾回收器。
pc寄存器:每一个线程拥有一个pc寄存器,pc寄存器总是指向下一条指令地址。执行本地的方法时,是未定义的。
方法区:保存类的元信息的。就是class信息,用来描述类的信息,类型的常量池,字段,方法信息,方法字节码。(jdk6:是把常量信息置于方法区。jdk7:常量已经移到了堆)通常和永久区关联在一起。
本地方法栈:本地方法栈与虚拟机栈所发挥的作用是非常相似的,它们之间的区别不过是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则为虚拟机使用到的Native方法服务。
堆:和程序开发最为密切的,因为new出来的对象,都是在java堆里面分配的。所以的线程共享java堆。对分代GC来说,堆也是分代的。
栈:线程私有的。栈又叫帧栈,先进后出的数据结构,帧保存一个方法的局部变量、操作数栈、常量池指针,每一次方法调用创建一个帧,并压栈。
栈上分配:堆上分配,每次需要清理空间。栈上分配,函数调用完成自动清理。
可见性:一个线程修改了变量,其他线程可以立即知道
保证可见性的方法:1.volatile 2.synchronized(unlock之前,写变量值回主存) 3.final(一单初始化完成,其他线程就可见 )
有序性:在本线程内,操作都是有序的,在线程外观察,操作都是无序的。(指令重排 或 主内存同步延时)
启动GC:-verbose:GC
堆分配参数:
-Xmx:最大堆
-Xms:最小堆
-Xmn:新生代大小
-XX:NewRatio:新生代 比例值
栈分配参数:栈空间应该分配比较小,线程运行是不可缺少的,一般是几百k容量,栈是每一个线程起来的时候都会被分配的一个空间,如果想尽量跑一些线程,就应该设置小点。栈大小决定了函数调用的深度,比如递归调用,如果栈太小就会导致栈溢出。
-Xss:几百k,决定了函数调用的
GC:GC的对象就是堆空间和永久区。
回收垃圾的算法:
1. 引用计数法:通过引用计算来垃圾回收(老牌垃圾回收算法),为每个对象标记一个使用数量,当对象引用数量为0的时候,就可以被回收。
引用方法问题:1. 随着引用的加法和减法,影响性能。 2.很难处理循环引用。
2.标记清除法:垃圾回收分为标记阶段和清除对象。在标记阶段通过根节点,标记所以从根节点开始的可达对象。清除阶段清理未标记的对象。
3.标记压缩法:在标记清除法做了一些优化。但是清除并不是清除未标记的对象,而是将存活对象压缩到内存的另外一端。之后清理边界外所有的空间。
4.复制算法:将内存分为两块,只使用其中的一块,将存活的对象复制到未使用的内存块中,清除正在使用的内存块中的所有对象,交换两个对象角色,完成回收。(浪费空间)
new对象:父类静态块>子类静态块> 父类属性(先系统默认值,后直接你赋予的值) >父类构造器>子类属性>子类构造器
this和super
从本质上讲,this是一个指向本对象的指针, 然而super是一个Java关键字。
super()和this()类似,区别是,super()从子类中调用父类的构造方法,this()在同一类内调用其它方法。
类(class)加载过程:加载 -> 校验 -> 准备 -> 解析 -> 初始化 -> 使用 -> 卸载
1. 加载:
加载一个Class需要完成以下3件事情:
- 通过class的全限定名获取class的二进制字节流
- 将class的二进制内容加载到虚拟机的方法区
- 在内存中生成一个java.long.ckass对象表示这个class
获取class的二进制字节流方法:
由其他文件生成,典型的是从jsp文件生成相应的class
2. 校验:
校验一个class的二进制内容是否合法:文件格式验证 -> 元数据验证 -> 字节码验证 -> 符号应用验证
3. 准备:虚拟机会在方法区中为class分配内存,并设置static成员变量的初始值为默认值。
4. 解析:
主要针对的是类、接口、方法、成员变量等符号应用。
线程:
Q:如何创建一个线程?
A:实现Runnable接口,继承Thread类
Q:实现Runnable接口,继承Thread类 那个好呢?
A:Java不支持类的多重继承,但允许你调用多个接口。所以如果你要继承其他类,当然是调用Runnable接口好 了。
Q:Thread 类中的start() 和 run() 方法有什么区别
A:start()方法被用来启动新创建的线程,而且start()内部 调用了run()方法,这和直接调用run()方法的效果不一样。当你调用run()方法的时候,只会是在原来的线程中调用,没有新的线程启 动,start()方法才会启动新线程。
Q:volatile 变量是什么?
A:volatile是一个特殊的修饰符,只有成员变量才能使用它。
Q:如何避免死锁?
A:死锁是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。这是一个严重的问题,因为死锁会让你的程序挂起无法完成任务,死锁的发生必须满足以下四个条件:
- 互斥条件:一个资源每次只能被一个进程使用。
- 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
- 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
- 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
避免死锁最简单的方法就是阻止循环等待条件,将系统中所有的资源设置标志位、排序,规定所有的进程申请资源必须以一定的顺序(升序或降序)做操作来避免死锁。
Q:怎么检测一个线程是否拥有锁?
A:在Thread中有一个方法叫holdsLock(),它返回true如果当且仅当当前线程拥有某个具体对象的锁。
Q:wait()与sleep()的区别
A:sleep()睡眠后不出让系统资源,wait让其他线程可以占用CPU
Q:什么是多线程的上下文切换?
A:多线程的上下文切换是指CPU控制权由一个已经正在运行的线程切换到另外一个就绪并等待获取CPU执行权的线程的过程。
Q:Synchronized 和 lock 区别?
A:Lock是一个接口,而synchronized是关键字。synchronized会自动释放锁,而Lock必须手动释放锁。Lock能提高多个线程读操作的效率。synchronized能锁住类、方法和代码块,而Lock是块范围内的
拦截器和过滤器:
监听器:是servlet规范中定义的一种特殊类。用于监听域对象的创建和销毁事件。使用场景:1.统计在线人数和在线用户 2.系统启动时加载初始化信息 3.统计网站访问量 4.记录用户访问路径。
区别:
1.拦截器是基于java的反射机制,而过滤器是基于函数回调。
2.拦截器不依赖与servlet容器,过滤器依赖与servlet容器。
3.拦截器只能对action请求起作用,而过滤器则可能对几乎所有的请求起作用。
4.在action的生命周期中, 拦截器可以多次被调用,而过滤器在初始化时被调用一次。
5.拦截器可以获取ioc容器中的各个bean,而过滤器就不行,在拦截器里注入一个service,可以调用业务逻辑。
执行顺序:
拦截器创建:
1.实现Handler Interceptor接口,重写里面的方法,实现业务逻辑代码
2.用java代码进行配置拦截器
addPathPatterns("/**")添加了所有的都拦截。
过滤器创建:
1.在启动类增加@ServletComponentScan注解
2.配置过滤器,需要实现filter接口,然后配置注解@WebFilter,设定filter的名称和过滤地址
监听器创建:
自定义一个类实现ApplicationListener即可,具体监听什么事件,讲事件填入到泛型中
Spring IOC和AOP:
上下文:负责加载在xml或者是java代码中配置bean的相关信息。
ioc:是一种编程思想,它的设计思想是想把创建对象,管理对象的生命周期,程序集直接的解耦工作交给第三方容器来处理。传统的方式都是自己new一个对象,然后再写一个公共类去维护这个对象的生命周期。用了IOC组件之后这些操作就交由第三方ioc容器组件来处理,只需要把对象塞进容器里,并告诉容器这个对象的生命周期就可以了。 创建对象的几种方式: 1.调用无参构造器 2.带参构造器 3.工厂创建对象:静态方法创建对象,非静态方法创建对象 什么情况下会用构造器注入:对强依赖使用构造器注入,对可选择性的依赖使用属性注入 spring提供了三种主要的方式来配置: 1.在xml中进行显式配置 2.在java中进行显式配置,javaConfig 3.隐式的bean发现机制和自动装配 @Autowired:实现自动装配 @Qualifier:解决多个相同类型的bean,指定beanaop: 使用场景:缓存,持久化,同步,事务 AOP的源码中用到了两种动态代理来实现拦截切入功能: jdk动态代理和cglib动态代理。 两种方法同时存在,各有优劣。jdk动态代理是由java内部的反射机制来实现的,cglib动态代理底层则是借助asm来实现的。总的来说,反射机制在生成类的过程中比较高效,而asm在生成类之后的相关执行过程中比较高效(可以通过将asm生成的类进行缓存,这样解决asm生成类过程低效问题)
设计模式:
工厂模式:
使用目的:定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。
优点:
1.一个调用者想创建一个对象,只要知道其名称就可以了。
2.扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。
3.屏蔽产品的具体实现,调用者只关心产品的接口。
缺点:1.每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。
使用场景:1.日志记录器:记录肯记录到本地硬盘、系统事件、远程服务器等,太湖可以选择记录日志到什么地方。