java面试题大全

一、基础

  1. 线程和进程区别

1、定义不一样,进程是执行中的一段程序,而一个进程中执行中的每个任务即为一个线程。
2、一个线程只可以属于一个进程,但一个进程能包含多个线程。
3、线程无地址空间,它包括在进程的地址空间里。
4、线程的开销或代价比进程的小。
  1. 创建线程的四种方式

1)继承Thread类创建线程
2)实现Runnable接口创建线程
3)使用Callable和Future创建线程
4)使用线程池例如用Executor框架
  1. 乐观锁的实现方式,什么是 CAS?

悲观锁和乐观锁都是一种思想;
悲观锁:独占锁、阻塞锁,在对数据进行操作实时默认会发生冲突,会对数据操作加上锁,当一个线程获得锁以后,其它线程必须等待当前线程
释放锁才能获得锁,悲观锁的实现往往依靠数据库的锁机制.
悲观锁存在的问题:1.
1.在多线程竞争的环境下,频繁地加锁、释放锁会导致比较多的上下问切换
2.一个线程拥有锁会导致其它要竞争此锁的线程挂起

乐观锁:非独占锁,非阻塞锁,乐观锁就是假设没有冲突去完成某项操作,如果发生冲突就重试,直到成功为止。
CAS:CAS是一项乐观锁技术,当多个线程尝试去更新某一个共享变量时,只有一个线程会更新成功,其他更新失败的线程
不会被挂起,并可以再次尝试。
CAS操作包含三个操作数:内置位置(V)预期原值(A)新值(B):如果内置位置的值和预期原值相匹配,处理器会将内置位置的值
更新为新值,否则处理器不做任何操作。CAS就是乐观锁思想的一种实现方式,也是非阻塞算法的一种实现。
J.U.C包就是建立在CAS之上的,没有锁的机制下要借助volatile
CAS容易出现的三个问题:
1. 注意:CAS可能导致ABA问题,就是一个线程1先将A变成B,然后又将数据变成A,此时线程1发现内置位置仍是A,就会操作成功,但并不代表这个
操作过程就没有问题。
解决ABA问题:部分乐观锁的实现是通过版本号(version)来解决ABA问题的,每次去修改/更新一个数据时,会带上版本号,一旦版本号和数据的版本号
一致时就会一致就可以执行修改/更新操作,并将版本号+1;
2.多线程竞争时,线程长时间拿不到锁会做无意义的自旋,给CPU资源带来一定程度的消耗。
3.只能保证一个共享变量的原子性操作
  1. 什么是死锁?

死锁的概念是什么?
死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。
解决方法:
在系统中已经出现死锁后,应该及时检测到死锁的发生,并采取适当的措施来解除死锁。
死锁预防。
这是一种较简单和直观的事先预防的方法。方法是通过设置某些限制条件,去破坏产生死锁的四个必要条件中的一个或者几个,来预防发生死锁。预防死锁是一种较易实现的方法,已被广泛使用。但是由于所施加的限制条件往往太严格,可能会导致系统资源利用率和系统吞吐量降低。
死锁避免。
系统对进程发出的每一个系统能够满足的资源申请进行动态检查,并根据检查结果决定是否分配资源;如果分配后系统可能发生死锁,则不予分配,否则予以分配。这是一种保证系统不进入死锁状态的动态策略。
死锁检测和解除。
先检测:这种方法并不须事先采取任何限制性措施,也不必检查系统是否已经进入不安全区,此方法允许系统在运行过程中发生死锁。但可通过系统所设置的检测机构,及时地检测出死锁的发生,并精确地确定与死锁有关的进程和资源。检测方法包括定时检测、效率低时检测、进程等待时检测等。
然后解除死锁:采取适当措施,从系统中将已发生的死锁清除掉。
这是与检测死锁相配套的一种措施。当检测到系统中已发生死锁时,须将进程从死锁状态中解脱出来。常用的实施方法是撤销或挂起一些进程,以便回收一些资源,再将这些资源分配给已处于阻塞状态的进程,使之转为就绪状态,以继续运行。死锁的检测和解除措施,有可能使系统获得较好的资源利用率和吞吐量,但在实现上难度也最大。
  1. 死锁与活锁的区别,死锁与饥饿的区别?

死锁
是指两个或者两个以上的进程(或线程)在执行过程中, 因争夺资源而造成的一种互相等待的现象, 若无外力作用,他们将无法推进下去。
产生死锁的原因
互相争夺共享资源
产生死锁的共享条件
互斥条件:共享资源被一个线程占用
请求与保持条件(占有且等待):一个进程因请求资源而被阻塞时,对已经获得资源保持不释放
不可剥夺条件(不可抢占):进程已获得资源,在未使用完之前,不能进行剥夺
循环等待条件:多个线程 循环等待资源,而且是循环的互相等待
只需要破坏上面 4 个条件中的一个就能破坏。
请求与保持条件:放大锁范围,去除对资源的抢占
不剥夺:换成可重入锁ReentrantLock
循环等待:改成顺序加锁,避免循环等待
互斥是多线程的特性,所以这个条件无法避免
活锁
任务或者执行者没有被阻塞,由于某些条件没有满足,导致一直重复尝试、失败、尝试、失败。在这期间线程状态会不停的改变
活锁与死锁的区别
死锁会阻塞,一直等待对方释放资源,一直处在阻塞状态;活锁会不停的改变线程状态尝试获得资源。
活锁有可能自行解开,死锁则不行
饥饿
一个或者多个线程因为种种原因无法获得所需要的资源,导致一直无法执行的状态。一直有线程级别高的暂用资源,线程低的一直处在饥饿状态。 比如ReentrantLock显示锁里提供的不公平锁机制,不公平锁能够提高吞吐量但不可避免的会造成某些线程的饥饿
死锁与饥饿的区别
线程处于饥饿是因为不断有优先级高的线程占用资源,当不再有高优先级的线程争抢资源时,饥饿状态将会自动解除。
产生饥饿的原因:【即线程一直在等待却无法执行的原因】
高优先级线程抢占资源
线程在等待一个本身也处于永久等待完成的对象
线程被永久阻塞在一个等待进入同步块的状态,因为其他线程总是能在他之前持续地对该同步块进行访问(比如阻塞在synchronized)
  1. Java有哪些数据类型?

布尔数据类型
字节数据类型
字符数据类型
短数据类型
整数数据类型
长数据类型
浮点数据类型
双数据类型
布尔数据类型
  1. final有什么用?

1,final修饰类,表示类不可变,不可扩展(不可继承),即不能有子类
2,final修饰方法,表示该方法不可重写
3,final修饰变量,这个变量就是常量
  1. 介绍下static

1、static称为静态修饰符,它可以修饰类中得成员。被static修饰的成员被称为静态成员,也成为类成员,而不用static修饰的成员称为实例成员。
2、当 Voluem volu1 = new Volume(); (在java中)
Voluem volu2 = new Volume();
就是产生了两个新的对象volu1和volu2,这两个对象都各自拥有自己的成员存储空间,而不与其他对象共享。
所创建的对象均由各自的存储空间来保存自己的值,而不与其他对象共享。这些成员变量(例如radius)各自相互独立,且存在于不同的内存之中。具有此特性的成员变量,java中称为实例变量(instance variable)

3、用static修饰的成员变量称为“静态变量”,静态变量也称为类变量。静态变量隶属于类的变量,而不属于任何一个类的具体对象。也就是说,对于类的任何一个具体对象而言,静态变量是个公共的存储单元,不保存在某个对象实例的内存空间中,而是保存在类的内存空间中得公共存储单元中。或者说,对于类的任何一个具体对象而言,静态变量是一个公共的存储单元,任何一个类的对象访问它的时候,去的都是一个相同的数值。同样,任何一个类的对象去修改它时,也都是对同一个内存单元进行操作。

4、它的引用方式:不需要实例化就可以直接用类去调用。也可以通过实例对象调用。

5、若类中含有静态变量,则静态变量必须独立于方法之外,就像其他高级语言在声明全局变量时必须在函数之外声明一样。

6、若对于静态方法,由于静态方法是属于整个类的,所以它不能操纵和处理属于某个对象的成员,而只能处理属于整个类的成员,即static方法只能访问static成员变量或者调用static成员方法,或者说在静态方法中不能访问实例变量或者实例方法。

7、在静态方法中也不能使用this或者super。因为this代表调用该方法的对象,但是现在静态方法既然不需要对象来调用,this也自然不应存在于静态方法内部。

8、对于静态方法,调用时与静态变量差不多,可以用类名直接调用,也可以用某一个具体的对象名来调用。


总之,对于加上static修饰符的成员或者方法,他们直接就可以使用类名调用而且不用实例化类之后再调用,而且一个地方修改了static修饰的成员,那么这个成员在所有地方的调用结果也都将改变。
  1. "=="和equals方法究竟有什么区别? 答案

  1)对于==,如果作用于基本数据类型的变量,则直接比较其存储的 “值”是否相等;
    如果作用于引用类型的变量,则比较的是所指向的对象的地址
  2)对于equals方法,注意:equals方法不能作用于基本数据类型的变量
    如果没有对equals方法进行重写,则比较的是引用类型的变量所指向的对象的地址;
    诸如String、Date等类对equals方法进行了重写的话,比较的是所指向的对象的内容。
  1. java只有值传递,不存在引用传递

Java规范说Java中的一切都是值传递的。在Java中没有所谓的“引用传递”。
  1. String s="Hello"; s=s+"world!";这两行代码执行后,原始的String对象中的内容到底变了没有?

答案是没有变。因为String是不可变类,不可变类,顾名思义就是说类的实例是不可被修改的。实例的信息是在创建的时候提供,并且在整个生命周期中都不可改变。在这段代码中,s原来指向一个String对象,内容是“hello”,然后我们对s进行了"+"操作,那么s所指向的那个对象是否发生了改变呢?答案是没有。这时,s不指向原来那个对象了,而指向了另一个String对象,内容为”helloworld!",原来那个对象还存在内存中,只是s这个引用变量不再指向他了。
通过上面的说明,我们很容易得出一个结论,如果经常对字符串进行各种各样的修改,或者说,不可预见的修改,那么使用String来代表字符串的话会引起很大的内存开销。因为,String对象建立后不能改变,所以对于每一个不同的字符串,都需要一个String对象来表示。这时,应该考虑使用StringBuffer类,他允许修改,而不是每个不同的字符串都要生成一个新的对象。并且,这两种类的对象转换十分容易。
对于字符串常量,如果内容相同,Java认为它们代表同一个String对象。而用关键字new调用构造器,总是会创建一个新的对象,无论内容是否相同。
至于为什么要把String类设计成不可变类,是它的用途决定的。其实不只String,很多Java标准类库中的类都是不可变的。在开发一个系统的时候,我们有时候也需要设计不可变类,来传递一组相关的值,这也是面向对象思想的体现。不可变类有一些优点,比如因为它的对象是只读的,所以多线程并发访问也不会有任何问题。当然也有一些缺点,比如每个不同的状态都要一个对象来代表,可能会造成性能上的问题。所以Java标准类库还提供了一个可变版本,即 StringBuffer。
  1. Error 和Exception的区别是什么?

error和exception的区别:中文含义不同、用法不同。error作为名词,含义为“错误”、“差错”,一般表示很难恢复;exception作为名词,含义为“例外”、“一般情况以外的人”、“规则的例外”。
  1. java程序初始化顺序是怎样的?

1.初始化父类静态变量
2.初始化父类的静态代码块
3.初始化子类的静态变量
4.初始化子类的静态代码块
5.父类的非静态变量
6.父类的非静态代码块
7.父类的构造函数
8.子类的非静态变量
9.子类的非静态代码块
10.子类的构造函数
  1. java 中 IO 流分为几种?它们的区别是什么?

分两大种,输入流和输出流
输入流分为字节输入流,字符输入流

输出流分为字节输出流,字符输出流

这四大类各自有各自的分支,各有各的功能,但总的来说主要是这四种。
字符流读速写速要比字节流快,没有乱码现象,但是它只能读写文档(txt);字节流可以读写任意文件。
java.io下是java的IO流
以下是几种常用流
FileInputStream文件字节输入流
FileOutputStream文件字节输出流
FileReader文件字符输入流
FileWriter文件字符输出流
  1. String为什么使用final修饰?

1、为了实现字符串连接池
final可以修饰类方法和变量,被final修饰的类不能被继承。
String被final所修饰主要是为了“安全性”和“效率”。
final修饰String代表String不可继承,final修饰的char[]数组存储的数据是可以改变的。
2、为了线程安全
为了在多线程共享是安全的,否则会引起错乱。
3、为了实现String可以创建HashCode不可变性。
提高效率
String类经常作为哈希表中的key,经常要使用到其hash值,基于String不可变的特性,可以对其hash值进行缓存,减少重复运算,String类有一个成员变量hash,对hash值进行了缓存
提高资源的利用率
String是最常用的对象,为了节省内存,基于String不可变的特性,可以实现字符串常量池。
创建String对象前,jvm会先检查字符串常量池中是否存在该对象,若存在则直接返回其引用,否则新建一个对象并缓存进常量池,再返回引用。
字符串常量池避免了重复String对象的创建,节省了内存资源,同时由于减少了对象创建的次数,也提高了程序的执行效率
保证线程安全
String是不可变的,因此不必担心String对象会被其他线程改变,天生线程安全
  1. 如何自定义注解?

@Retention: 表示该注解的生命周期,是RetentionPolicy类型的,该类型是一个枚举类型,可提供三个值选择,分别是:CLASS、RUNTIME、SOURCE
RetentionPolicy.CLASS: 注解被保留到class文件,但jvm加载class文件时候被遗弃,这是默认的生命周期;
RetentionPolicy.RUNTIME: 注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在;
RetentionPolicy.SOURCE: 注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃;
由此可见生命周期关系:SOURCE < CLASS < RUNTIME,我们一般用RUNTIME
@Target: 表示该注解的作用范围,是ElementType类型的,该类型是一个枚举类型,一共提供了10个值选择,我们最常用的几个:FIELD、TYPE、PARAMETER、METHOD
ElementType.FIELD:用于字段、枚举的常量
ElementType.TYPE:用于接口、类、枚举、注解
ElementType.PARAMETER:用于方法参数
ElementType.METHOD:用于方法
  1. 什么是hashCode()?

hashCode()是Object定义的方法,它将返回一个整型值,它并不代表对象在内存中的地址,它存在的价值是为Hash容器处理数据时提供支持,Hash容器可以根据hashCode定位需要使用的对象,也可以根据hashCode来排除2个不相同的对象,即:hashCode不同,则视为2个对象不同
  1. 什么是多态?java 中实现多态的机制是什么?

多态是允许你将父对象设置成为一个或更多的他的子对象相等的技术。
我们在程序中定义的引用变量所指向的具体类型和通过该引用变量的方法调用在编程的时候并不确定,当处于运行期间才确定。就是这个引用变量究竟指向哪一个实例对象,在编译期间是不确定的,只有运行期才能确定,这样不用修改源码就可以把变量绑定到不同的类实例上,让程序拥有了多个运行状态,这就是多态。
  1. 重载和重写的区别有哪些?

重载和重写的区别是什么?
重写多态性起作用,对调用被重载过的方法可以大大减少代码的输入量,同一个方法名只要往里面传递不同的参数就可以拥有不同的功能或返回值。用好重写和重载可以设计一个结构清晰而简洁的类,可以说重写和重载在编写代码过程中的作用非同一般。
重载和重写的区别如下
1.定义不同---重载是定义相同的方法名,参数不同;重写是子类重写父类的方法。
2.范围不同---重载是在一个类中,重写是子类与父类之间的。
3.多态不同---重载是编译时的多态性,重写是运行时的多态性。
4.返回不同---重载对返回类型没有要求,而重写要求返回类型,有兼容的返回类型。
5.参数不同---重载的参数个数、参数类型、参数顺序可以不同,而重写父子方法参数必须相同。
6.修饰不同---重载对访问修饰没有特殊要求,重写访问修饰符的限制一定要大于被重写方法的访问修饰符。
  1. java重载为什么与返回值无关?

因为java里允许调用一个有返回值的方法的时候不必将返回值赋给变量,这样JVM就不知道你调用的是有返回值的还是没返回值的。
  1. 抽象类和普通类的区别

1、抽象类的存在时为了被继承,不能实例化,而普通类存在是为了实例化一个对象
2、抽象类的子类必须重写抽象类中的抽象方法,而普通类可以选择重写父类的方法,也可以直接调用父类的方法
3、抽象类必须用abstract来修饰,普通类则不用
4、普通类和抽象类都可以含有普通成员属性和普通方法
5、普通类和抽象类都可以继承别的类或者被别的类继承
6、普通类和抽象类的属性和方法都可以通过子类对象来调用
  1. 抽象类和接口的区别

1、抽象类和接口都不能直接实例化,如果要实例化,抽象类变量必须指向实现所有抽象方法的子类对象,接口变量必须指向实现所有接口方法的类对象。
2、抽象类要被子类继承,接口要被类实现。
3、接口只能做方法申明,抽象类中可以做方法申明,也可以做方法实现
4、接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量。
5、抽象类里的抽象方法必须全部被子类所实现,如果子类不能全部实现父类抽象方法,那么该子类只能是抽象类。同样,一个实现接口的时候,如不能全部实现接口方法,那么该类也只能为抽象类。
6、抽象方法只能申明,不能实现,接口是设计的结果 ,抽象类是重构的结果
7、抽象类里可以没有抽象方法
8、如果一个类里有抽象方法,那么这个类只能是抽象类
9、抽象方法要被实现,所以不能是静态的,也不能是私有的。
10、接口可继承接口,并可多继承接口,但类只能单根继承。
  1. 什么是反射、反射能干什么、如何使用反射?

一、什么是反射
反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。其中LEAD/LEAD++ 、OpenC++ 、MetaXa和OpenJava等就是基于反射机制的语言。最近,反射机制也被应用到了视窗系统、操作系统和文件系统中。
反射本身并不是一个新概念,尽管计算机科学赋予了反射概念新的含义。在计算机科学领域,反射是指一类应用,它们能够自描述和自控制。也就是说,这类应用通过采用某种机制来实现对自己行为的描述(self-representation)和监测(examination),并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。
二、什么是Java中的类反射
Reflection 是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说“自审”,并能直接操作程序的内部属性和方法。Java 的这一能力在实际应用中用得不是很多,但是在其它的程序设计语言中根本就不存在这一特性。例如,Pascal、C 或者 C++ 中就没有办法在程序中获得函数定义相关的信息。
Reflection 是 Java 被视为动态(或准动态)语言的关键,允许程序于执行期 Reflection APIs 取得任何已知名称之 class 的內部信息,包括 package、type parameters、superclass、implemented interfaces、inner classes, outer class, fields、constructors、methods、modifiers,並可于执行期生成instances、变更 fields 內容或唤起 methods。
三、Java类反射中所必须的类
Java的类反射所需要的类并不多,它们分别是:Field、Constructor、Method、Class、Object,下面我将对这些类做一个简单的说明。
Field类:提供有关类或接口的属性的信息,以及对它的动态访问权限。反射的字段可能是一个类(静态)属性或实例属性,简单的理解可以把它看成一个封装反射类的属性的类。
Constructor类:提供关于类的单个构造方法的信息以及对它的访问权限。这个类和Field类不同,Field类封装了反射类的属性,而Constructor类则封装了反射类的构造方法。
Method类:提供关于类或接口上单独某个方法的信息。所反映的方法可能是类方法或实例方法(包括抽象方法)。 这个类不难理解,它是用来封装反射类方法的一个类。
Class类:类的实例表示正在运行的 Java 应用程序中的类和接口。枚举是一种类,注释是一种接口。每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。
Object类:每个类都使用 Object 作为超类。所有对象(包括数组)都实现这个类的方法。
  1. 创建对象有几种方式?

使用new关键字 → 调用了构造函数
使用Class类的newInstance方法 → 调用了构造函数
使用Constructor类的newInstance方法 → 调用了构造函数
使用clone方法 → 没有调用构造函数
使用反序列化 → 没有调用构造函数
  1. 如何提高反射效率?

1、缓存重复用到的对象
利用缓存,其实我不说大家也都知道,在平时项目中用到多次的对象也会进行缓存,谁也不会多次去创建。
2、setAccessible(true)
之前我们说过当遇到私有变量和方法的时候,会用到setAccessible(true)方法关闭安全检查。这个安全检查其实也是耗时的。
所以我们在反射的过程中可以尽量调用setAccessible(true)来关闭安全检查,无论是否是私有的,这样也能提高反射的效率。
  1. 类加载器有哪些?

1 启动类加载器(Bootstrap ClassLoader)用来加载java核心类库,无法被java程序直接引用。
2 扩展类加载器(extensions class loader):它用来加载 Java 的扩展库。Java 虚拟机的实现会提供 一个扩展库目录。该类加载器在此目录里面查找并加载 Java 类。
3 系统类加载器(system class loader):它根据 Java 应用的类路径(CLASSPATH)来加载 Java 类。一般来说,Java 应用的类都是由它来完成加载的。可以通过ClassLoader.getSystemClassLoader()来获取它。
4 用户自定义类加载器,通过继承 java.lang.ClassLoader类的方式实现。
  1. 类加载的方式有几种,它们的区别是什么?

1使用new
new className()
2 使用 Class.forName("classPath")
3 使用classLoader
获得ClassLoader 加载类
三种方式的区别:
1 使用new 只能加载当前classPath 中的类 使用一种静态的加载方式
2 使用Class.forName() 动态加载 只能加载当前claspath 中的类 是一种动态加载
3 classLoader 动态加载 可以自己书写classLoader 加载的类可以不是classpath中的类

Class.forName() 和 classLoader 的区别
Class.forName() 加载类的时候会初始化 static 只能加载classpath 中的类
ClassLoader 初始化时不会初始static 中的代码 可以加载 不是classpath中的类
  1. 了解下对象分配空间的两种分配方式

方式一:指针碰撞
在Java中,当类被加载完成后,就能够确定其对应的对象所需的内存大小是多少,此时就需要从Java堆中划分出一块确定大小的内存块来为对象分配相应的空间。如果Java堆中的内存是绝对规整的,已被使用的内存和空闲内存各占一边,泾渭分明,二者之间的分界点通过一个指针来表示,那接下来分配内存的操作就是把指针往空闲空间方向挪动一段与对象大小相等的距离,这种分配方式就叫做”指针碰撞“。
方式二:空闲列表
而如果Java堆中的内存不是规整的,已被使用的内存和空闲内存交错混淆在一起,就没法通过指针碰撞的分配方式来为对象分配空间了,虚拟机就会维护一个列表,该列表上记录着哪些内存块是可用的,然后在为对象分配空间时,就会从列表中找到一个足够大的内存空间划分给对象实例,这种分配方式就叫做”空闲列表“。
总结
而具体选择以上两种分配方式的哪种,由Java堆是否绝对规整决定,而Java堆是否规整又由所采用的垃圾收集器决定,而垃圾回收器是否带有空间压缩整理能力决定了其规整堆的能力。
  1. JVM调优工具

jps:虚拟机进程状况工具:查看当前运行的java进行,后面的许多命令都是基于此命令找到pid再进一步排查问题。

jstat:虚拟机统计信息监视工具,如每隔10s监视jvm的运行状态

jinfo:用来查看正在运行的 java 应用程序的扩展参数,包括Java System属性和JVM命令行参数;也可以动态的修改正在运行的 JVM 一些参数。

jmap: java内存映像工具 (在jdk9及以上,jmap工具被jhsdb jmap代替),用于查看整个JVM内存状态
详细的使用方法见文章: https://www.jianshu.com/p/c0a5219aede2

jhat:虚拟机堆转储快照分析工具

jhat用于对JAVA heap进行离线分析的工具,他可以对不同虚拟机中导出的heap信息文件进行分析,如LINUX上导出的文件可以拿到WINDOWS上进行分析,可以查找诸如内存方面的问题,使用方式可以查看这篇文章: https://blog.csdn.net/gtuu0123/article/details/6039474

jstack:java堆栈跟踪工具

HSDIS:jit生成代码反汇编

jconsole:图形工具,监控jvm运行情况

jvisualvm:个人感觉visualVm比jconsole功能更强大一些,默认携带的功能包括监视CPU,堆的总占用,线程和加载类信息,heapdump等。
  1. JVM加载class文件的原理机制是什么(JVM的类加载的原理机制是什么)?

虚拟机(jvm)把描述类的数据从Class文件加载到内存,并对数据进行校验,解析和初始化,最终形成可以被虚拟机直接使用的java类型。
  java中的所有类,都需要有由类加载器装载到JVM中才能运行。类加载器本身也是一个类,而它的工作就是把Class文件从硬盘读取到内存中。在写程序的时候,我们几乎不需要关心类的加载,因为这些都是隐式装载的,除非我们有特殊的用法,像是反射,就需要显示的加载所需要的类。
类装载的方式,有两种:
1、隐式装载,程序在运行过程中当碰到通过new等方式生成对象时,隐式调用类装载器对应的类到jvm中
2、显示装载,通过class.forname()等方式,显示加载需要的类
  java类的加载是动态的,它并不会一次性将所有类全部加载后再运行,而是保存程序运行的基础类(像是基类)完全加载到JVM中,至于其他类,则在需要的时候才才加载。这当然就是为了节省内存开销
  1. 什么是集合?集合和数组的区别。

一、指代不同
1、集合:是数学中一个基本概念,也是集合论的主要研究对象。
2、数组:将有限个类型相同的变量的集合命名,是有序的元素序列。
二、用处不同
1、集合:指具有某种特定性质的具体的或抽象的对象汇总而成的集体。其中,构成集合的这些对象则称为该集合的元素 。
2、数组:是在程序设计中,为了处理方便, 把具有相同类型的若干元素按无序的形式组织起来的一种形式。 这些无序排列的同类数据元素的集合称为数组。
三、特征不同
1、集合:给定一个集合,任给一个元素,该元素或者属于或者不属于该集合,二者必居其一,不允许有模棱两可的情况出现。
2、数组:一个数组可以分解为多个数组元素,这些数组元素可以是基本数据类型或是构造类型。因此按数组元素的类型不同,数组又可分为数值数组、字符数组、指针数组、结构数组等各种类别。
  1. 常用的集合类有哪些?它们的区别是什么?

1、ArrayList和Vector的区别
答:
这两个类都实现了List接口(List接口继承了Collection接口),他们都是有序集合,即存储在这两个集合中的元素的位置都是有顺序的,相当于一种动态的数组,我们以后可以按位置索引号取出某个元素,,并且其中的数据是允许重复的,这是HashSet之类的集合的最大不同处,HashSet之类的集合不可以按索引号去检索其中的元素,也不允许有重复的元素(本来题目问的与hashset没有任何关系,但为了说清楚ArrayList与Vector的功能,我们使用对比方式,更有利于说明问题)。
接着才说ArrayList与Vector的区别,这主要包括两个方面:.
(1)同步性:
Vector是线程安全的,也就是说是它的方法之间是线程同步的,而ArrayList是线程序不安全的,它的方法之间是线程不同步的。如果只有一个线程会访问到集合,那最好是使用ArrayList,因为它不考虑线程安全,效率会高些;如果有多个线程会访问到集合,那最好是使用Vector,因为不需要我们自己再去考虑和编写线程安全的代码。
(2)数据增长:
ArrayList与Vector都有一个初始的容量大小,当存储进它们里面的元素的个数超过了容量时,就需要增加ArrayList与Vector的存储空间,每次要增加存储空间时,不是只增加一个存储单元,而是增加多个存储单元,每次增加的存储单元的个数在内存空间利用与程序效率之间要取得一定的平衡。Vector默认增长为原来两倍,而ArrayList的增长策略在文档中没有明确规定(从源代码看到的是增长为原来的1.5倍)。ArrayList与Vector都可以设置初始的空间大小,Vector还可以设置增长的空间大小,而ArrayList没有提供设置增长空间的方法。
2、HashMap和Hashtable的区别
(条理上还需要整理,也是先说相同点,再说不同点)
HashMap是Hashtable的轻量级实现(非线程安全的实现),他们都完成了Map接口,主要区别在于HashMap允许空(null)键值(key),由于非线程安全,在只有一个线程访问的情况下,效率要高于Hashtable。
HashMap允许将null作为一个entry的key或者value,而Hashtable不允许。
HashMap把Hashtable的contains方法去掉了,改成containsvalue和containsKey。因为contains方法容易让人引起误解。
Hashtable继承自Dictionary类,而HashMap是Java1.2引进的Map interface的一个实现。
最大的不同是,Hashtable的方法是Synchronize的,而HashMap不是,在多个线程访问Hashtable时,不需要自己为它的方法实现同步,而HashMap 就必须为之提供外同步。
Hashtable和HashMap采用的hash/rehash算法都大概一样,所以性能不会有很大的差异。
就HashMap与HashTable主要从三方面来说。
一.历史原因:Hashtable是基于陈旧的Dictionary类的,HashMap是Java 1.2引进的Map接口的一个实现
二.同步性:Hashtable是线程安全的,也就是说是同步的,而HashMap是线程序不安全的,不是同步的
三.值:只有HashMap可以让你将空值作为一个表的条目的key或value
3、List 和 Map 区别?
一个是存储单列数据的集合,另一个是存储键和值这样的双列数据的集合,List中存储的数据是有顺序,并且允许重复;Map中存储的数据是没有顺序的,其键是不能重复的,它的值是可以有重复的。
4、List, Set, Map是否继承自Collection接口?
List,Set是,Map不是
5、List、Map、Set三个接口,存取元素时,各有什么特点?
List 以特定次序来持有元素,可有重复元素。Set 无法拥有重复元素,内部排序。Map 保存key-value值,value可多值。
HashSet按照hashcode值的某种运算方式进行存储,而不是直接按hashCode值的大小进行存储。例如,“abc” —> 78,“def” —> 62,“xyz” —> 65在hashSet中的存储顺序不是62,65,78,这些问题感谢以前一个叫崔健的学员提出,最后通过查看源代码给他解释清楚,看本次培训学员当中有多少能看懂源码。LinkedHashSet按插入的顺序存储,那被存储对象的hashcode方法还有什么作用呢?学员想想!hashset集合比较两个对象是否相等,首先看hashcode方法是否相等,然后看equals方法是否相等。new 两个Student插入到HashSet中,看HashSet的size,实现hashcode和equals方法后再看size。
同一个对象可以在Vector中加入多次。往集合里面加元素,相当于集合里用一根绳子连接到了目标对象。往HashSet中却加不了多次的。
6、说出ArrayList,Vector, LinkedList的存储性能和特性
ArrayList和Vector都是使用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,它们都允许直接按序号索引元素,但是插入元素要涉及数组元素移动等内存操作,所以索引数据快而插入数据慢,Vector由于使用了synchronized方法(线程安全),通常性能上较ArrayList差,而LinkedList使用双向链表实现存储,按序号索引数据需要进行前向或后向遍历,但是插入数据时只需要记录本项的前后项即可,所以插入速度较快。
LinkedList也是线程不安全的,LinkedList提供了一些方法,使得LinkedList可以被当作堆栈和队列来使用。
7、Collection 和 Collections的区别。
Collection是集合类的上级接口,继承与他的接口主要有Set 和List.
Collections是针对集合类的一个帮助类,他提供一系列静态方法实现对各种集合的搜索、排序、线程安全化等操作。
  1. java怎么实现动态代理?有什么意义?

链接
  1. synchronized的作用

1、synchronized的作用
synchronized 的作用主要有三:
(1)、原子性:**所谓原子性就是指一个操作或者多个操作,要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行。**被synchronized修饰的类或对象的所有操作都是原子的,因为在执行操作之前必须先获得类或对象的锁,直到执行完才能释放。
(2)、可见性:**可见性是指多个线程访问一个资源时,该资源的状态、值信息等对于其他线程都是可见的。 **synchronized和volatile都具有可见性,其中synchronized对一个类或对象加锁时,一个线程如果要访问该类或对象必须先获得它的锁,而这个锁的状态对于其他任何线程都是可见的,并且在释放锁之前会将对变量的修改刷新到共享内存当中,保证资源变量的可见性。
(3)、有序性:有序性值程序执行的顺序按照代码先后执行。 synchronized和volatile都具有有序性,Java允许编译器和处理器对指令进行重排,但是指令重排并不会影响单线程的顺序,它影响的是多线程并发执行的顺序性。synchronized保证了每个时刻都只有一个线程访问同步代码块,也就确定了线程执行同步代码块是分先后顺序的,保证了有序性。

四种锁
无锁状态
偏向锁
| 偏向锁 | 线程在大多数情况下并不存在竞争条件,使用同步会消耗性能,而偏向锁是对锁的优化,可以消除同步,提升性能。当一个线程获得锁,会将对象头的锁标志位设为01,进入偏向模式。偏向锁可以在让一个线程一直持有锁,在其他线程需要竞争锁的时候,再释放锁 | 加锁和解锁不需要额外的消耗,和执行非同步方法相比仅存在纳秒级的差距 | 如果线程间存在锁竞争,会带来额外的锁撤销的消耗 | 适用于只有一个线程访问同步块的场景 |’
* | 轻量级锁 |
* | 轻量级锁 | 当线程A获得偏向锁后,线程B进入竞争状态,需要获得线程A持有的锁,那么线程A撤销偏向锁,进入无锁状态。线程A和线程B交替进入临界区,偏向锁无法满足,膨胀到轻量级锁,锁标志位设为00 | 竞争的线程不会阻塞,提高了程序的相应速度 | 如果始终得不到所竞争的线程,使用自旋会消耗CPU | 追求相应速度,同步块执行速度非常块 |
* | 重量级锁 | 当多线程交替进入临界区,轻量级锁hold得住。但如果多个线程同时进入临界区,hold不住了,膨胀到重量级锁 | 线程竞争不使用自旋,不会消耗CPU | 线程阻塞,响应时间缓慢 | 追求吞吐量,同步块执行速度较慢 |
- 会同时被多个线程访问的资源,就是竞争资源(临界资源),也称为竞争条件。对于多线程
共享的资源(临界资源)必须进行同步,以避免一个线程的改动被另一个线程所覆盖。
  1. volatile关键字的作用

https://blog.csdn.net/xinghui_liu/article/details/124379221
  1. 线程怎么保持同步?

https://zhuanlan.zhihu.com/p/463279312
  1. 什么是java中的CAS

CAS是 compare and swap的缩写,即我们所说的比较交换。cas是一种基于锁的操作,而且是乐观锁
https://blog.csdn.net/u011381576/article/details/79922538
  1. Lock与synchronized的区别

区别:
1.synchronized是关键字,Lock是接口;
2.synchronized是隐式的加锁,lock是显式的加锁;
3.synchronized可以作用于方法上,lock只能作用于方法块;
4.synchronized底层采用的是objectMonitor,lock采用的AQS;
5.synchronized是阻塞式加锁,lock是非阻塞式加锁支持可中断式加锁,支持超时时间的加锁;
6.synchronized在进行加锁解锁时,只有一个同步队列和一个等待队列, lock有一个同步队列,可以有多个等待队列;
7.synchronized只支持非公平锁,lock支持非公平锁和公平锁;
8.synchronized使用了object类的wait和notify进行等待和唤醒, lock使用了condition接口进行等待和唤醒(await和signal);
9.lock支持个性化定制, 使用了模板方法模式,可以自行实现lock方法;
相同点:
1.Lock是一个接口,为了使用一个Lock对象,需要用到;
2.Lock lock = new ReentrantLock();
3.与 synchronized (someObject) 类似的,lock()方法,表示当前线程占用lock对象,一旦占用,其他线程就不能占用了;
4.与synchronized 不同的是,一旦synchronized 块结束,就会自动释放对someObject的占用。 lock却必须调用unlock方法进行手动释放,为了保证释放的执行,往往会把unlock() 放在finally中进行;
5.synchronized 是不占用到手不罢休的,会一直试图占用下去;
6.与 synchronized 的钻牛角尖不一样,Lock接口还提供了一个trylock方法;
7.trylock会在指定时间范围内试图占用。 如果时间到了,还占用不成功,就选择放弃;
注意: 因为使用trylock有可能成功,有可能失败,所以后面unlock释放锁的时候,需要判断是否占用成功了,如果没占用成功也unlock,就会抛出异常;
8.使用synchronized方式进行线程交互,用到的是同步对象的wait,notify和notifyAll方法;
9.Lock也提供了类似的解决办法,首先通过lock对象得到一个Condition对象,然后分别调用这个Condition对象的:await, signal,signalAll 方法;
注意: 不是Condition对象的wait,nofity,notifyAll方法,是await,signal,signalAll;
不同点:
1.Lock是一个接口,而synchronized是Java中的关键字,synchronized是内置的语言实现,Lock是代码层面的实现;
2.Lock可以选择性的获取锁,如果一段时间获取不到,可以放弃。synchronized不行,会一根筋一直获取下去。 借助Lock的这个特性,就能够规避死锁,synchronized必须通过谨慎和良好的设计,才能减少死锁的发生;
3.synchronized在发生异常和同步块结束的时候,会自动释放锁。而Lock必须手动释放, 所以如果忘记了释放锁,一样会造成死锁。
  1. MyBatis

MyBatis 是支持普通 SQL查询,存储过程和高级映射的优秀持久层框架。MyBatis 消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索。MyBatis 使用简单的 XML或注解用于配置和原始映射,将接口和 Java 的POJOs(Plain Ordinary Java Objects,普通的 Java对象)映射成数据库中的记录。
  1. 什么是ORM?

ORM是一种思想,ORM (全称为 :Object Relative Mapping)对象-关系映射
,关系数据库是企业级应用环境中永久存放数据的主流数据存储系统。对象和关系数据是业务实体的两种表现形式,业务实体在内存中表现为对象,在数据库中表现为关系数据。内存中的对象之间存在关联和继承关系,而在数据库中,关系数据无法直接表达多对多关联和继承关系。因此,对象-关系映射(ORM)系统一般以中间件的形式存在,主要实现程序对象到关系数据库数据的映射。
ORM模型的简单性简化了数据库查询过程。使用ORM查询工具,用户可以访问期望数据,而不必理解数据库的底层结构。
  1. 为什么说 Mybatis 是半自动 ORM 映射工具?它与全自动的区别在哪里?

Hibernate是一种全自动ORM映射工具,使用Hibernate查询相关对象或相关集合对象时,可以直接基于对象关系模型检索,因此是全自动的。 另一方面,Mybatis被称为半自动ORM映射工具,因为在查询相关对象或相关集合对象时,必须手动创建和完成sql。
  1. 传统JDBC开发存在的问题

1、数据库连接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库连接池可解决此问题。
2、Sql 语句在代码中硬编码,造成代码不易维护,实际应用sql变化的可能较大,sql 变动需要改变 java 代码。
3、使用 preparedStatement 向占有位符号传参数存在硬编码,因为 sql 语句的 where 条件不一定,可能多也可能少,修改 sql 还要修改代码,系统不易维护。
4、对结果集解析存在硬编码(查询列名),sql 变化导致解析代码变化,系统不易维护,如果能将数据库记录封装成 pojo 对象解析比较方便。
  1. JDBC编程有哪些不足之处,MyBatis是如何解决这些问题的?

问题一:SQL 语句写在代码中造成代码不易维护,且代码会比较混乱。
解决方式:将 SQL 语句配置在 Mapper XML 文件中,与 Java 代码分离。
问题二:根据参数不同,拼接不同的 SQL 语句非常麻烦。例如 SQL 语句的 WHERE 条件不一定,可能多也可能少,占位符需要和参数一一对应。
解决方式:MyBatis 提供 、 等等动态语句所需要的标签,并支持 OGNL 表达式,简化了动态 SQL 拼接的代码,提升了开发效率。
问题三,对结果集解析麻烦,SQL 变化可能导致解析代码变化,且解析前需要遍历。
解决方式:Mybatis 自动将 SQL 执行结果映射成 Java 对象。
问题四,数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题。
解决方式:在 mybatis-config.xml 中,配置数据链接池,使用连接池管理数据库链接。
  1. Mybatis优缺点

一、MyBatis框架的优点:
  1. 与JDBC相比,减少了50%以上的代码量。
  2. MyBatis是最简单的持久化框架,小巧并且简单易学。
  3. MyBatis灵活,不会对应用程序或者数据库的现有设计强加任何影响,SQL写在XML里,从程序代码中彻底分离,降低耦合度,便于统一管理和优化,可重用。
  4. 提供XML标签,支持编写动态SQL语句(XML中使用if, else)。
  5. 提供映射标签,支持对象与数据库的ORM字段关系映射(在XML中配置映射关系,也可以使用注解)。
二、MyBatis框架的缺点:
  1. SQL语句的编写工作量较大,尤其是字段多、关联表多时,更是如此,对开发人员编写SQL语句的功底有一定要求。
  2. SQL语句依赖于数据库,导致数据库移植性差,不能随意更换数据库。
三、MyBatis框架适用场合:
  MyBatis专注于SQL本身,是一个足够灵活的DAO层解决方案。
  对性能的要求很高,或者需求变化较多的项目,如互联网项目,MyBatis将是不错的选择。
  1. MyBatis的解析和运行原理

mybatis工作原理:mybatis配置文件,包括Mybatis全局配置文件和Mybatis映射文件,其中全局配置文件配置了数据源、事务等信息;映射文件配置了SQL执行相关的信息。mybatis通过读取配置文件信息(全局配置文件和映射文件),构造出SqlSessionFactory,即会话工厂。
通过SqlSessionFactory,可以创建SqlSession即会话。Mybatis是通过SqlSession来操作数据库的。SqlSession本身不能直接操作数据库,它是通过底层的Executor执行器接口来操作数据库的。Executor接口有两个实现类,一个是普通执行器,一个是缓存执行器(默认)。Executor执行器要处理的SQL信息是封装到一个底层对象MappedStatement中。
  1. #{}和${}的区别


1、#{}是一个占位符,相当于JDBC中的占位符PrepareStatement?,会对一些敏感的字符进行过滤;
2、#{}底层采用的是PreparedStatement,会预编译(主要是里面的setString方法,对一些特殊的字符,例如’'单引号,会在值后面加上一个\右斜线进行转义,让值无效),因此不会产生sql注入;
3、#{}不会产生字符串拼接;
4、#{}在使用时会根据传递进来的值来选择是否加上双引号(例:#{name} 传入sql中就是"小明");
5、在传递参数时#{}中可以传递任意值;
6、#{}的应用场景是为sql语句中where字句传递条件值;

1、{}匹配的是真是传递的值,传递后会与sql语句进行字符拼接
2、${}会与其他sql进行字符串拼接,不能预防sql注入
3、不会主动加 " " 双引号
4、{}作为普通传值,不能进行字符过滤
5、${}的应用场景是为了传递一些需要参与SQL语句语法生成的值
  1. 在mapper中如何传递多个参数

1、第一种:使用参数下标
DAO层的函数
publicUserselectUser(String name,String area);
对应的xml,#{0}代表接收的是dao层中的第一个参数,#{1}代表dao层中第二参数,更多参数一致往后加即可。
<selectid="selectUser"resultMap="BaseResultMap">
select * fromuser_user_t whereuser_name = #{0} anduser_area=#{1}
</select>
2、第二种:使用 @param 注解
3、第三种:多个参数封装成map
  1. MyBatis执行批量操作

第一种方法:使用foreach标签
第二种方法:使用ExecutorType.BATCH
  1. 简述Mybatis的Xml映射文件和Mybatis内部数据结构之间的映射关系?


  Mybatis将所有Xml配置信息都封装到All-In-One重量级对象Configuration内部.在Xml映射文件中,<parameterMap>标签会被解析为
  ParameterMap对象,其每个子元素会被解析为ParameterMapping对象.
  <resultMap>标签会被解析为ResultMap对象,其每个子元素会被解析为ResultMapping对象.每一个<Select>,<insert>,<update>,
  <delete>标签均会被解析为MappedStatement对象,标签内的SQL会被解析为Bounds对象.
  1. 什么是Spring?Spring是什么?

Spring是一个开源框架,是为了解决企业应用程序开发复杂性而开发的。
从简单性、可測试性和松耦合的角度而言,不论什么java应用都能够从Spring中受益。
简而言之,Spring就是一个轻量级的控制反转(IOC)和面向切面(AOP)的容器框架。
https://blog.csdn.net/weixin_30240349/article/details/98808102
https://blog.csdn.net/guorui_java/article/details/104254041
  1. Spring的优缺点是什么?为什么要用Spring?

一、spring框架的优点:
spring 是一个开源的轻量级 JavaBean 容器框架。使用 JavaBean 代替 EJB ,并提供了丰富的企业应用功能,降低应用开发的复杂性。
**Spring的优缺点是什么?**
1.方便解耦,便于开发(Spring就是一个大工厂,可以将所有对象的创建和依赖关系维护都交给spring管理)
2.spring支持aop编程(spring提供面向切面编程,可以很方便的实现对程序进行权限拦截和运行监控等功能)
3.声明式事务的支持(通过配置就完成对事务的支持,不需要手动编程)
4.方便程序的测试,spring 对junit4支持,可以通过注解方便的测试spring 程序
5.方便集成各种优秀的框架()
6.降低javaEE API的使用难度(Spring 对javaEE开发中非常难用的一些API 例如JDBC,javaMail,远程调用等,都提供了封装,是这些API应用难度大大降低)
**简而言之,我们使用Spring有如下的原因:**
1.Spring是 开源 的 轻量级 框架
2.一站式框架,内部支持对多种优秀开源框架的集成。
3.Spring 核心 主要有两部分:
(1)AOP:面向切面编程,扩展功能不是修改源代码实现。
(2)IOC:控制反转。创建对象不是通过new方式来实现,而是交给Spring配置来创建对象。

二、spring框架的缺点
1、中断了应用程序的逻辑,使代码变得不完整,不直观。此时单从Source无法完全把握应用的所有行为。
2、将原本应该代码化的逻辑配置化,增加了出错的机会以及额外的负担。
3、时光倒退,失去了IDE的支持。在目前IDE功能日益强大的时代,以往代码重构等让人头痛的举动越来越容易。而且IDE还提供了诸多强大的辅助功能,使得编程的门槛降低很多。通常来说,维护代码要比维护配置文件,或者配置文件+代码的混合体要容易的多。
4、调试阶段不直观,后期的bug对应阶段,不容易判断问题所在。
5、spring像一个胶水,将框架黏在一起,后面拆分的话就不容易拆分了。
  1. spring ioc循环依赖

答:三级缓存
实例化A的时候,先将A创建(早期对象)放入一个池子(singletonFactories)中。这个时候虽然属性没有赋值,但是容器已经能认识这个是A对象,只是属性全是null而已。在populateBean方法中对属性赋值的时候,发现A依赖了B,那么就先去创建B,又走一遍bean的创建过程(创建B)。同样也会把B的早期对象放入缓存(singletonFactories)中。当B又走到 populateBean方法(负责填充Bean实例属性的方法)的时候,发现依赖了A,我们又去创建A,但是这个时候去创建A,发现我们在缓存(singletonFactories)能找到A(早期对象),此时会通过A的ObjectFactory获取A,并把A从三级缓存移到二级缓存。然后就可以把B的A属性赋值了,这个时候B就初始化完成了,初始化完成后就会把B从三级缓存移到一级缓存。完成B实例化后,回到A调用的populateBean方法中。返回的就是B对象了,对A的B属性进行赋值就可以了。

IOC无法解决的两种循环依赖
一是非单例对象,因为非单例对象不会放入缓存的。每次都是需要创建。
二是通过构造器注入,也无法解决。从上面的流程可以看出,调用构造器创建实例是在createBeanInstance方法,而解决循环依赖是在populateBean(负责属性注入的方法)这个方法中,执行顺序也决定了无法解决该种循环依赖。
  1. 什么是AOP-面向切面编程

https://blog.csdn.net/longzorg_cn/article/details/127989341
  1. 静态代理和动态代理的区别是什么?

静态代理和动态代理的区别
1、静态代理通常只代理一个类,动态代理是代理一个接口下的多个实现类。
2、静态代理事先知道要代理的是什么,而动态代理不知道要代理什么东西,只有在运行时才知道。
3、动态代理是实现JDK里的InvocationHandler接口的invoke方法,但注意的是代理的是接口,也就是你的业务类必须要实现接口,通过Proxy里的newProxyInstance得到代理对象。
4、还有一种动态代理CGLIB,代理的是类,不需要业务类继承接口,通过派生的子类来实现代理。通过在运行时,动态修改字节码达到修改类的目的。
静态代理
​ 某个对象提供一个代理,代理角色固定,以控制对这个对象的访问。 代理类和委托类有共同的父类或父接口,这样在任何使用委托类对象的地方都可以用代理对象替代。代理类负责请求的预处理、过滤、将请求分派给委托类处理、以及委托类执行完请求后的后续处理。
静态代理的特点
1、目标角色固定
2、在应用程序执行前就得到目标角色
3、代理对象会增强目标对象的行为
4、有可能存在多个代理 引起"类爆炸"(缺点)
动态代理
​ 相比于静态代理,动态代理在创建代理对象上更加的灵活,动态代理类的字节码在程序运行时,由Java反射机制动态产生。它会根据需要,通过反射机制在程序运行期,动态的为目标对象创建代理对象,无需程序员手动编写它的源代码。
动态代理的特点
1、目标对象不固定
2、在应用程序执行时动态创建目标对象
3、代理对象会增强目标对象的行为

线程池的七大参数

**线程池的七大参数**:
1.corePoolSize:线程池中的常驻核心线程数
2.maxinumPoolSize:线程池中能够容纳同时执行的最大线程数,此值必须大于等于一
3.keepAliveTime:多余的空闲线程的存活时间。
当前线程池数量超过corePoolSize时,当空闲时间达到keepAliveTime时,多余空闲线程会被销毁直到只剩下corePoolSize个线程为止。
4.unit:keepAliveTime的单位
5.workQueue:任务队列,被提交但是尚未被执行的任务。
6.threadFactory:表示生成线程池中工作线程的线程工厂,用于创建线程一般用默认的即可。
7.handler:拒绝策略,表示当队列满了并且工作线程-大于等于线程池的数量最大线程数(maxinumPoolSize)时如何来拒绝请求执行的runnable的策略。
https://blog.csdn.net/weixin_41520357/article/details/125253303

线程池的拒绝策略

AbortPolicy(默认):丢弃任务并抛出 RejectedExecutionException 异常。
CallerRunsPolicy:由调用线程处理该任务。
DiscardPolicy:丢弃任务,但是不抛出异常。可以配合这种模式进行自定义的处理方式。
DiscardOldestPolicy:丢弃队列最早的未处理任务,然后重新尝试执行任务。

消息队列满了以后该怎么处理?

https://blog.csdn.net/assholeCai/article/details/120596618

kafka和mq的区别

kafka和mq的主要区别是:RabbitMQ,遵循AMQP协议,由内在高并发的erlanng语言开发,用在实时的对可靠性要求比较高的消息传递上;kafka是Linkedin于2010年12月份开源的消息发布订阅系统,它主要用于处理活跃的流式数据,大数据量的数据处理上。
下面我们来详细介绍它们的区别。
一、 语言不同
RabbitMQ是由内在高并发的erlanng语言开发,用在实时的对可靠性要求比较高的消息传递上。
kafka是采用Scala语言开发,它主要用于处理活跃的流式数据,大数据量的数据处理上。
二、 架构模型不同
RabbitMQ遵循AMQP协议,RabbitMQ的broker由Exchange,Binding,queue组成,其中exchange和binding组成了消息的路由键;客户端Producer通过连接channel和server进行通信,Consumer从queue获取消息进行消费(长连接,queue有消息会推送到consumer端,consumer循环从输入流读取数据)。rabbitMQ以broker为中心;有消息的确认机制。
kafka遵从一般的MQ结构,producer,broker,consumer,以consumer为中心,消息的消费信息保存的客户端consumer上,consumer根据消费的点,从broker上批量pull数据;无消息确认机制。
三、 Brokerr与Consume交互方式不同
RabbitMQ 采用push的方式。
kafka采用pull的方式。
四、吞吐量不同
rabbitMQ在吞吐量方面稍逊于kafka,他们的出发点不一样,rabbitMQ支持对消息的可靠的传递,支持事务,不支持批量的操作;基于存储的可靠性的要求存储可以采用内存或者硬盘。
kafka具有高的吞吐量,内部采用消息的批量处理,zero-copy机制,数据的存储和获取是本地磁盘顺序批量操作,具有O(1)的复杂度,消息处理的效率很高。
五、可用性不同
rabbitMQ支持miror的queue,主queue失效,miror queue接管。
kafka的broker支持主备模式。
六、集群负载均衡不同
rabbitMQ的负载均衡需要单独的loadbalancer进行支持。
kafka采用zookeeper对集群中的broker、consumer进行管理,可以注册topic到zookeeper上;通过zookeeper的协调机制,producer保存对应topic的broker信息,可以随机或者轮询发送到broker上;并且producer可以基于语义指定分片,消息发送到broker的某分片上。
七、使用场景不同
rabbitMQ支持对消息的可靠的传递,支持事务,不支持批量的操作;基于存储的可靠性的要求存储可以采用内存或者硬盘。金融场景中经常使用。
kafka具有高的吞吐量,内部采用消息的批量处理,zero-copy机制,数据的存储和获取是本地磁盘顺序批量操作,具有O(1)的复杂度(与分区上的存储大小无关),消息处理的效率很高。(大数据)

redis是否支持事务?

redis是支持事务的,通过multi开启事务,通过exec提交事务,
通过discard取消事务,但是redis的事务是,不支持自动回滚的,
在事务中,如果执行了多条命令,有一条执行失败了,其他的命令还是正常执行。

事务的4个属性

原子性、一致性、隔离性、持久性。这四个属性通常称为ACID特性。

mysql引擎类型

1、InnoDB 引擎
MySQL 5.5 及以后版本中的默认存储引擎,它的优点如下:灾难恢复性好,支持事务,使用行级锁,支持外键关联,支持热备份。
InnoDB引擎中的表,其数据的物理组织形式是簇表(Cluster Table),主键索引和数据是在一起的,数据按主键的顺序物理分布。实现了缓冲管理,不仅能缓冲索引也能缓冲数据,并且会自动创建散列索
引以加快数据的获取。
2、MyISAM引擎
它的特性如下:不支持事务;使用表级锁,并发性差;主机宕机后,MyISAM表易损坏,灾难恢复性不佳;可以配合锁,实现操作系统下的复制备份、迁移;只缓存索引,数据的缓存是利用操作系统缓
冲区来实现的。可能引发过多的系统调用且效率不佳;数据紧凑存储,因此可获得更小的索引和更快的全表扫描性能。
上面这两个是最常用的Mysql引擎。它们两者的主要区别:InnoDB支持事务,MyISAM不支持;MyISAM适合查询以及插入为主的应用,InnoDB适合频繁修改以及涉及到安全性较高的应用;InnoDB支持外键,MyISAM不支持;清空整个表时,InnoDB是一行一行的删除,效率非常慢。MyISAM则会重建表;InnoDB支持行锁,MyISAM的全表锁;InnoDB中不保存表的行数,如select count(*) from table时,InnoDB需要扫描一遍整个表来计算有多少行,但是MyISAM只要简单的读出保存好的行数即可。注意的是,当count(*)语句包含where条件时MyISAM也需要扫描整个表。
总之:MyISAM类型不支持事务处理等高级处理,而InnoDB类型支持;MyISAM类型的表强调的是性能,其执行速度比InnoDB类型更快,但是不提供事务支持,而InnoDB提供事务支持已经外部键等高级数据库功能。
3、MEMORY 存储引擎
提供内存表,也不支持事务和外键。显著提高访问数据的速度,可用于缓存会频繁访问的、可以重构的数据、计算结果、统计值、中间结果。但是它使用表级锁,虽然内存访问快,但如果频繁的读写,表
级锁会成为瓶颈;只支持固定大小的行;不支持TEXT、BLOB字段。当有些查询需要使用到临时表(使用的也是MEMORY存储引擎)时,如果表中有TEXT、BLOB字段,那么会转换为基于磁盘的MyISAM
表,严重降低性能。

redis都有哪些数据结构

Redis基本数据类型有String(字符串)、List(列表)、Hash(哈希)、Set(集合)、和Sorted Set(有序集合)

java 常用的设计模式

创建型模式(5种):工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式(7种):适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式(11种):策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值