JAVA后端开发面试经典

1.String的不可变性

一但一个字符串在堆内存创建,它是不能被改变的,我们应该注意所有的关于String类的方法不是改变一个字符串本身,而是重新返回一个新的字符串。

如果我们需要一个频繁的改变一个字符串对象,我们可以使用StringBuffer或者StringBuilder,否则将会浪费大量时间进行垃圾回收,因为每次创建一个新的字符串。不过需要注意的是,貌似JDK1.7之前不是所有的方法都是返回新对象,1.7的是返回新的对象。

StringBuffer是线程安全的,StringBuilder是线程不安全的,如果需要在一个方法内部初始化一个字符串常量,则使用StringBuilder效率最高,因为此时只会有一个线程,所以不用考虑线程是否安全。

效率String<StringBuffer<StringBuilder

字符串常量池(String pool, String intern pool, String保留池) 是Java堆内存中一个特殊的存储区域, 当创建一个String对象时,假如此字符串值已经存在于常量池中,则不会创建一个新的对象,而是引用已经存在的对象。

当string初始化一个字符串时,会先在内存中寻找,如果找到的话将引用直接指向,如果没找到,会分配一块内存。当需要改变这个string的值时,同样会先在内存中找。但是会将String所指向的地址改变到新的。原值没改变,只是没有引用指向,这就是String的不可变性。

2.java基本数据类型

bit就是位,byte就是字节,1byte = 8 bit,bit是计算机可处理的最小的数据类型

byte:8位,最大存储数据量是255,存放的数据范围是-128~127之间。

short:16位,最大数据存储量是65536,数据范围是-32768~32767之间。

int:32位,最大数据存储容量是2的32次方减1,数据范围是负的2的31次方到正的2的31次方减1。

long:64位,最大数据存储容量是2的64次方减1,数据范围为负的2的63次方到正的2的63次方减1。

float:32位,数据范围在3.4e-45~1.4e38,直接赋值时必须在数字后加上f或F。

double:64位,数据范围在4.9e-324~1.8e308,赋值时可以加d或D也可以不加。

boolean:只有true和false两个取值。

char:16位,存储Unicode码,用单引号赋值。

3.面向对象的特征

封装:把描述一个对象的属性和行为封装成一个类,把具体的业务逻辑功能实现封装成一个方法,其次封装的意义还有效的保护属性通过访问修饰符私有化属性(成员变量),公有化方法。

继承:实现代码的复用,所有的子类所共有的行为和属性抽取为一个父类,所有的子类继承该类可具备父类的属性和行为,继承具有单一性和传递性。

多态:程序中定义的引用类型变量所指向的具体类型和调用的具体方法在程序编译阶段无法确定,而是在运行期才能确定该引用类型变量指向具体哪个对象而调用在哪个类中声明的方法。

4.重载与重写

重载(Overload)是让类以统一的方式处理不同类型数据的一种手段。

实质表现就是多个具有不同的参数个数或者类型的同名函数(返回值类型可随意,不能以返回类型作为重载函数的区分标准)同时存在于同一个类中,是一个类中多态性的一种表现(调用方法时通过传递不同参数个数和参数类型来决定具体使用哪个方法的多态性)。与返回类型无关。

重写(Override)是父类与子类之间的多态性,实质是对父类的函数进行重新定义,如果在子类中定义某方法与其父类有相同的名称和参数则该方法被重写,不过子类函数的访问修饰权限不能小于父类的;若子类中的方法与父类中的某一方法具有相同的方法名、返回类型和参数表,则新方法将覆盖原有的方法,如需父类中原有的方法则可使用 super 关键字。

重写的特点:“两同两小一大”

两同:方法名和形参列表一致;

子类返回类型小于等于父类方法返回类型,

子类抛出异常小于等于父类方法抛出异常,

子类访问权限大于等于父类方法访问权限。

5.构造方法

java构造函数,也叫构造方法,是java中一种特殊的函数。函数名与相同,无返回值。

作用:一般用来初始化成员属性和成员方法的,即new对象产生后,就调用了对象了属性和方法。

构造函数的特点:

1、函数名与类名相同

2、不用定义返回值类型。(不同于void类型返回值,void是没有具体返回值类型;构造函数是连类型都没有)

3、不可以写return语句。(返回值类型都没有,也就不需要return语句了)

构造函数是对象一建立就运行,给对象初始化,就包括属性,执行方法中的语句。

而一般函数是对象调用才执行,用".方法名“的方式,给对象添加功能。

一个对象建立,构造函数只运行一次。

而一般函数可以被该对象调用多次。

6.throws和throw

Throw:

作用在方法内,表示抛出具体异常,由方法体内的语句处理。

具体向外抛出的动作,所以它抛出的是一个异常实体类。若执行了Throw一定是抛出了某种异常。

Throws:

作用在方法的声明上,表示如果抛出异常,则由该方法的调用者来进行异常处理。

主要的声明这个方法会抛出会抛出某种类型的异常,让它的使用者知道捕获异常的类型。

出现异常是一种可能性,但不一定会发生异常。

throw是语句抛出一个异常。

语法:throw (异常对象);

   throw e;

throws是方法可能抛出异常的声明。(用在声明方法时,表示该方法可能要抛出异常)

语法:(修饰符)(方法名)([参数列表])[throws(异常类)]{…}

public void doA(int a) throws Exception1,Exception3{…}

7.string和stringbuffer和stringbuilder的区别

String是Java中基础且重要的类,String被声明为final,除了hash这个属性其它属性都声明为final,因为它的不可变性,所以例如拼接字符串时候会产生很多无用的中间对象,如果频繁的进行这样的操作对性能有所影响。

StringBuffer就是为了解决大量拼接字符串时产生很多中间对象问题而提供的一个类,提供append和add方法,可以将字符串添加到已有序列的末尾或指定位置,它的本质是一个线程安全的可修改的字符序列,把所有修改数据的方法都加上了synchronized。

在很多情况下我们的字符串拼接操作不需要线程安全,这时候StringBuilder登场了,StringBuilder是JDK1.5发布的,它和StringBuffer本质上没什么区别,就是去掉了保证线程安全的那部分,减少了开销。

StringBuffer和StringBuilder类都表示内容可以修改的字符串,StringBuilder是线程不安全的,运行效率高,如果一个字符串是个方法里边定义,这种情况下只有一个线程访问它,不存在不安全因素,则用StringBuilder,如果在类里边定义,并且这个类的实例对象会在多线程下使用,那么就用StringBuffer

8.常用的集合框架

Map集合 HashMap和HashTable

	HashMap是HashTable 的轻量级实现,他们都实现了Map借口,HashMap允许键为空,值为空,由于是非线程安全的,所以只有一个线程时,它的效率要高于HashTable(不是线程安全的)

hashmap初始默认长度是16,并且每次增长都是2的幂次方

在jdk1.8之前采用的是链表进行存储,jdk1.8之后采用红黑树进行存储

	HashTable不允许null值作为键或者值,是线程安全的,现在目前不太频繁使用,因为现在有了ConcurrentHashMap这个专门用于多线程场景下的map实现类,其大大优化了多线程下的性能。

JDK1.7锁分段

ConcurrentHashMap利用锁分段技术增加了锁的数目,从而使争夺同一把锁的线程的数目得到控制。

锁分段技术就是对数据集进行分段,每段竞争一把锁,不同数据段的数据不存在锁竞争,从而有效提高 高并发访问效率

在JAVA的jdk1.8中则对ConcurrentHashMap又再次进行了大的修改,取消了segment段锁字段,采用了CAS+Synchronize技术来保障线程安全。底层采用数组+链表+红黑树的存储结构,也就是和HashMap一样。这里注意Node其实就是保存一个键值对的最基本的对象。其中Value和next都是使用的volatile关键字进行了修饰,以确保线程安全。

这里为什么使用volatile进行修饰?

因为volatile对所有线程都是立即可见的,可以保证可见性

1、令这个被修饰的变量的更新具有可见性,一旦该变量遭到了修改,其他线程立马就会知道,立马放弃自己在自己工作内存中持有的该变量值,转而重新去主内存中获取到最新的该变量值。

2、产生了内存屏障,这里volatile可以保证CPU在执行代码时保证,所有被volatile中被修饰的之前的一定在之前被执行,也就是所谓的“指令重排序”。

List集合

Set和List的区别:Set是无序的,值不可以重复

				List是有序的,值可以重复

ArrayList和LinkedList区别

	 ArrayList的实现用的是数组,LinkedList是基于链表,ArrayList适合查找,LinkedList适合增删

9.set如何确保数据的唯一性

set保证里面元素的唯一性其实是靠两个方法,一是equals()和hashCode()方法

往set里面添加数据的时候一般会有隐式的操作

先是判断set集合中是否有与新添加数据的hashcode值一致的数据,

如果有,那么将再进行第二步调用equals方法再进行一次判断,

假如集合中没有与新添加数据hashcode值一致的数据,那么将不调用eqauls方法。

1.equals()相等的两个对象他们的hashCode()肯定相等,也就是用equals()对比是绝对可靠的。

2.hashCode()相等的两个对象他们的equals()不一定相等,也就是hashCode()不是绝对可靠的。

10.接口的特点

接口中的属性只能是常量,由static,final修饰

接口中不能存在构造函数

接口中有公共的抽象方法,abstract 可以省略

在jdk1.8之后,接口中可以存在默认的方法,由default修饰,存在方法体

11.访问修饰符

			本类       同包不同类     不同包子类    所有地方
private      √
默认的		  √              √
protecte	√              √			√
public		√			   √            √            √

12.面向对象的7大原则:

单一职责原则:一个类只负责一个功能领域中的相应职责,否则就应该将类拆分

开闭原则:一个软件实体应该对外扩展开放,对修改关闭

里式代换原则:任何基类出现的地方,子类一定可以出现,也就是子类可以替换父类,反之不行。

合成/聚合复用原则:要尽量使用合成聚合,而不用继承

接口隔离原则:类之间的依赖关系应该建立在最小的接口上,使用多个专门的接口总比使用一个总接口要好

依赖倒置原则:面向接口编程,要依赖于抽象,而不依赖于具体,A类的控制权丢失,由容器创建实例,容器创建哪个,A类就使用哪个。

迪米特法则:又称最少知识原则,一个对象对另一个对象要尽量少的了解

13.接口与抽象类的区别:

抽象类
特点:
1.抽象类中可以构造方法
2.抽象类中可以存在普通属性,方法,静态属性和方法。
3.抽象类中可以存在抽象方法。
4.如果一个类中有一个抽象方法,那么当前类一定是抽象类;抽象类中不一定有抽象方法。
5.抽象类中的抽象方法,需要有子类实现,如果子类不实现,则子类也需要定义为抽象的。
接口
1.在接口中只有方法的声明,没有方法体。
2.在接口中只有常量,因为定义的变量,在编译的时候都会默认加上
public static final 
3.在接口中的方法,永远都被public来修饰。
4.接口中没有构造方法,也不能实例化接口的对象。
5.接口可以实现多继承
6.接口中定义的方法都需要有实现类来实现,如果实现类不能实现接口中的所有方法
7.则实现类定义为抽象类。
8、JDK1.8之后接口中可以出现default修饰的方法,有方法体,但是default不可以省略



抽象类关键字:abstract

	抽象类中的变量定义没有具体要求,抽象类中可以有抽象方法,也可以没有抽象方法,构造方法不能被抽象化。抽象类只能声明,不能实例化。

接口的关键字:interface

	接口中定义的属性只能是全局常量(public static final),方法只能是抽象方法,没有构造方法,不能实例化,只能声明,JDK1.8之后可以定义为default修饰的含有方法体的方法。

14、在面向对象中如何理解封装:

私有属性,公有方法。防止数据不正确,属性私有化后可以在方法中进行限制。

将复杂的功能逻辑封装起来,使得外部调用方更好的调用。

15、GC四个引用

1、强引用

如果一个对象具有强引用,它就不会被垃圾回收器回收。即使当前内存空间不足,JVM也不会回收它,而是抛出 OutOfMemoryError 错误,使程序异常终止。如果想中断强引用和某个对象之间的关联,可以显式地将引用赋值为null,这样一来的话,JVM在合适的时间就会回收该对象。

String str = "hello";    // 强引用
str = null;              // 取消强引用

2、软引用

在使用软引用时,如果内存的空间足够,软引用就能继续被使用,而不会被垃圾回收器回收;只有在内存空间不足时,软引用才会被垃圾回收器回收。

SoftReference<String> softName = new  SoftReference<>("张三");

3、弱引用

具有弱引用的对象拥有的生命周期更短暂。因为当 JVM 进行垃圾回收,一旦发现弱引用对象,无论当前内存空间是否充足,都会将弱引用回收。不过由于垃圾回收器是一个优先级较低的线程,所以并不一定能迅速发现弱引用对象。

WeakReference<String> weakName = new WeakReference<String>("hello");

4、虚引用

顾名思义,就是形同虚设,如果一个对象仅持有虚引用,那么它相当于没有引用,在任何时候都可能被垃圾回收器回收。

虚引用必须和引用队列关联使用,当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会把这个虚引用加入到与之关联的引用队列中。程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。如果程序发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。

ReferenceQueue<String> queue = new ReferenceQueue<String>();
PhantomReference<String> pr = new PhantomReference<String>(new String("hello"), queue);

16、final,finally、finalize

final最终,可以修饰常量,方法,类,修饰方法时不能被重写,修饰类时不能被继承,使用 final 关键字修饰一个变量时,是指引用变量不能变,引用变量所指向的对象中的内容还是可以改变的

finally在异常处理时提供 finally 块来执行任何清除操作。如果抛出一个异常,那么相匹配的 catch 子句就会执行,然后控制就会进入 finally 块(如果有的话)。

finalize

方法名。Java 技术允许使用 finalize()

方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没有被引用时对这个对象调用的。它是在

Object 类中定义的,因此所有的类都继承了它。子类覆盖 finalize()

方法以整理系统资源或者执行其他清理工作。finalize()

方法是在垃圾收集器删除对象之前对这个对象调用的。

注意:finalize不一定被jvm调用,只有当垃圾回收器要清除垃圾时才被调用。

17、Comparable 和Comparator比较器

题目,按年纪排序

1. 实现Comparable接口

缺陷:(1)实现该接口Comparable,对系统具有侵入性,代码高耦合。

(2)当以一个条件(age)排序时,虽然高耦合,但是还是可以实现的。若再以另一条件(weight)排序时,就无法解决。

1. 实现Comparator接口

优点:没有修改源文件,从新编写一个排序类(实现排序接口),对源文件没有侵入性,低耦合。
题目,按年纪排序

1. 实现Comparable接口

缺陷:(1)实现该接口Comparable,对系统具有侵入性,代码高耦合。

(2)当以一个条件(age)排序时,虽然高耦合,但是还是可以实现的。若再以另一条件(weight)排序时,就无法解决。

1. 实现Comparator接口

优点:没有修改源文件,从新编写一个排序类(实现排序接口),对源文件没有侵入性,低耦合。

18、HashMap与HashTable

1.  关于HashMap的一些说法:

a)  HashMap实际上是一个“链表散列”的数据结构,即数组和链表的结合体。HashMap的底层结构是一个数组,数组中的每一项是一条链表。

b)  HashMap的实例有俩个参数影响其性能: “初始容量” 和 装填因子。

c)  HashMap实现不同步,线程不安全。  HashTable线程安全

d)  HashMap中的key-value都是存储在Entry中的。

e)  HashMap可以存null键和null值,不保证元素的顺序恒久不变,它的底层使用的是数组和链表,通过hashCode()方法和equals方法保证键的唯一性

f)  解决冲突主要有三种方法:定址法,拉链法,再散列法。HashMap是采用拉链法(链地址法)解决哈希冲突的。

注: 链表法是将相同hash值的对象组成一个链表放在hash值对应的槽位;

   用开放定址法解决冲突的做法是:当冲突发生时,使用某种探查(亦称探测)技术在散列表中形成一个探查(测)序列。 沿此序列逐个单元地查找,直到找到给定 的关键字,或者碰到一个开放的地址(即该地址单元为空)为止(若要插入,在探查到开放的地址,则可将待插入的新结点存人该地址单元)。

  拉链法解决冲突的做法是: 将所有关键字为同义词的结点链接在同一个单链表中 。若选定的散列表长度为m,则可将散列表定义为一个由m个头指针组成的指针数 组T[0..m-1]。凡是散列地址为i的结点,均插入到以T[i]为头指针的单链表中。T中各分量的初值均应为空指针。在拉链法中,装填因子α可以大于1,但一般均取α≤1。拉链法适合未规定元素的大小。

   

2.  Hashtable和HashMap的区别:

a)   继承不同。

 public class Hashtable extends Dictionary implements Map

public class HashMap extends  AbstractMap implements Map

b)  Hashtable中的方法是同步的,而HashMap中的方法在缺省情况下是非同步的。在多线程并发的环境下,可以直接使用Hashtable,但是要使用HashMap的话就要自己增加同步处理了。

c)  Hashtable 中, key 和 value 都不允许出现 null 值。 在 HashMap 中, null 可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为 null 。当 get() 方法返回 null 值时,即可以表示 HashMap 中没有该键,也可以表示该键所对应的值为 null 。因此,在 HashMap 中不能由 get() 方法来判断 HashMap 中是否存在某个键, 而应该用 containsKey() 方法来判断。

d)  两个遍历方式的内部实现上不同。Hashtable、HashMap都使用了Iterator。而由于历史原因,Hashtable还使用了Enumeration的方式 。

e)  哈希值的使用不同,HashTable直接使用对象的hashCode。而HashMap重新计算hash值。

f)  Hashtable和HashMap它们两个内部实现方式的数组的初始大小和扩容的方式。HashTable中hash数组默认大小是11,增加的方式是old*2+1。HashMap中hash数组的默认大小是16,而且一定是2的指数。

 

注:  HashSet子类依靠hashCode()和equal()方法来区分重复元素。

     HashSet内部使用Map保存数据,即将HashSet的数据作为Map的key值保存,这也是HashSet中元素不能重复的原因。而Map中保存key值的,会去判断当前Map中是否含有该Key对象,内部是先通过key的hashCode,确定有相同的hashCode之后,再通过equals方法判断是否相同。

19、JDK与JRE的关系

JDK是给开发人员用的,JRE和JVM是普通用户用的。

JRE包含JVM,是JAVA的运行环境

jvm是java虚拟机,用来解释执行编译后的字节码文件(一般是.java源文件编译后的.class文件,其实也可以是其它一些语言的),你可以把它想象成就好比是一个CPU,执行程序各种指令,进行计算。

jre是java运行时环境,也就是提供运行Java程序能力的一套集合,所以其中肯定会包含有jvm,还有其它一些Java系统工具、类库等等。安装了jre,就表示可以运行java程序了。

jdk是Java开发工具包,给Java程序开发人员使用的。其中包括jre(开发完程序总要运行起来调试的吧),还包括其它一些开发时用到的工具,例如把.java源文件编译成.class字节码文件的javac工具,生成使用文档的javadoc工具等等。

20、非静态内部类引用外部类对象的方式?

类名.this.属性

21、java为什么可以跨平台

因为字节码是在虚拟机上运行的,而不是编译器。换而言之,是因为JVM能跨平台安装,所以相应JAVA字节码便可以跟着在任何平台上运行。只要JVM自身的代码能在相应平台上运行,即JVM可行,则JAVA的程序员就可以不用考虑所写的程序要在哪里运行,反正都是在虚拟机上运行,然后变成相应平台的机器语言。

22、类加载器有什么用?

类加载器(class loader)用来加载 Java 类到 Java 虚拟机中。一般来说,Java 虚拟机使用 Java 类的方式如下:Java 源程序(.java 文件)在经过 Java 编译器编译之后就被转换成 Java 字节代码(.class 文件)。类加载器负责读取 Java 字节代码,并转换成 java.lang.Class类的一个实例。每个这样的实例用来表示一个 Java 类。通过此实例的 newInstance()方法就可以创建出该类的一个对象。实际的情况可能更加复杂,比如 Java 字节代码可能是通过工具动态生成的,也可能是通过网络下载的。

23、java有垃圾收集器可以对那些不使用的对象进行垃圾回收,在内存中之中清除掉,为什么还要使用close()方法来关闭流了,这不是显得有点多余吗?

close()方法的意思是关闭此流和与该流相关的所有系统资源,这里为什么还要提到系统资源了?

这是因为在生成流对象时,不仅是在JVM中占用资源,相对操作系统的来说,也要为流开辟资源,对java垃圾收集器来说,操作系统分配的外部资源他是无能为力的,所以对于这些外部资源就只能调用close()方法将那些资源关闭掉!

24、在使用try-catch有多个catch时,要注意什么问题?

一个try块后有两个catch块,这很正常,因为,在try块中包含众多语句,可能抛出多种不同的异常,只有通过多个catch块来捕获不同的异常。

而如果两个异常存在继承关系,应该把子类异常放在你类异常的前面来捕获.

25、进程和线程的区别

进程是系统资源分配的单位,线程是程序执行的单位

进程包含线程,线程可资源共享。

26、多线程的如下方式

Thread类,runnable接口,当一个类已经继承了一个类之后就只能通过实现runnable接口来实现多线程。

27、什么是守护线程?有什么特点?

守护线程拥有自动结束自己生命周期的特性,而非守护线程不具备这个特点。

java中的垃圾回收就是一个守护线程。

28、.内存泄漏和内存溢出区别?

内存泄漏(memory leak)是指一个程序在申请内存空间后,无法正常释放该内存,导致GC无法自动回收,导致内存减少。这称为内存泄漏。

内存溢出(out of memory)是指一个程序在申请一块内存空间时,没有足够的内存来存储数据,比如开了一块int类型的空间来存储数据,但是你却要存储long型的数据,这就会导致内存溢出。

关系:内存泄漏最终就会导致内存溢出。

29、如何实现对象克隆

1). 实现Cloneable接口并重写Object类中的clone()方法;

    2). 实现Serializable接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆

浅克隆的话,对于基本数据类型会自动分配内存空间去指向,而对于引用类型数据会指向原有的对象地址。

深克隆:不管是神魔类型的数据,都会为之开辟新的内存空间。

30、谈谈你对类加载器的理解?

类加载器就是讲字节码文件加载到JVM中解释运行

类加载分为两种,一种是显式加载,一种是隐式加载

启动类加载器、扩展类加载器、应用类加载器(系统类加载器)、用户自定义类加载器。 

启动类加载器:这个类负责将存放在JAVA_HOME/lib目录或者被-Xbootclasspath参数所指定的路径中的并且是虚拟机内存中。

扩展类加载器:负责加载JAVA_HOME/lib/ext目录中或者被java.ext.dirs系统变量指定路径中的所有类库,开发者可以直接使用扩展类加载器。

应用程序类加载器:负责加载用户类路径上指定的类加载器,一般情况下就是程序中默认的类加载器。

双亲委派:首先查看这个类是否被加载,如果没有则调用父类的loadClass方法,直到BootstrapClassLoader(没有父类),我们把这个过程叫做双亲模式,如果父类加载器不能加载此类,再去尝试自行加载这个class。

全盘负责:有点类似“连坐”,一个类有A加载器加载,那么它所引用的,依赖的类也全部由A来加载。

缓存机制:与一般缓存机制一致一样,所有加载过的类实例存起来,当调用某个实例时,先从缓冲区查找,若缓冲区下存在,才会加载该类的二进制数据。

31、transient关键字的作用?

1,一旦变量被transient修饰,变量将不再是对象持久化的一部分,该变量内容在序列化后无法获得访问。

2,transient关键字只能修饰变量,而不能修饰方法和类。注意,本地变量是不能被transient关键字修饰的。变量如果是用户自定义类变量,则该类需要实现Serializable接口。

3,一个静态变量不管是否被transient修饰,均不能被序列化。

加了该关键字就可以避免被序列化

序列化,可以自实现另一个接口,重写其中的方法,就可以自实现一个序列化类。

32、volatile关键字的作用?

解析:出于运行速率的考虑,java编译器会把经常经常访问的变量放到缓存(严格讲应该是工作内存)中,读取变量则从缓存中读。但是在多线程编程中,内存中的值和缓存中的值可能会出现不一致。volatile用于限定变量只能从内存中读取,保证对所有线程而言,值都是一致的。但是volatile不能保证原子性,也就不能保证线程安全。
Syconized可以保证原子性,也可以保证可见性,所以就可以保证线程安全。

· 禁止了指令重排

· 保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量值,这个新值对其他线程是立 即可见的

· 不保证原子性(线程不安全)

32、TCP和UDP

TCP面向连接,用户数据报协议,UDP是传输控制协议

UDP一般用于传输视频等可掉帧的,因为UDP不可靠

1.基于连接与无连接

2.TCP要求系统资源较多,UDP较少;

3.UDP程序结构较简单

4.流模式(TCP)与数据报模式(UDP);

5.TCP保证数据正确性,UDP可能丢包

6.TCP保证数据顺序,UDP不保证

 TCP(Transmission Control Protocol)可靠的、面向连接的协议(eg:打电话)、传输效率低全双工通信(发送缓存&接收缓存)、面向字节流。使用TCP的应用:Web浏览器;电子邮件、文件传输程序。

   UDP(User Datagram Protocol)不可靠的、无连接的服务,传输效率高(发送前时延小),一对一、一对多、多对一、多对多、面向报文,尽最大努力服务,无拥塞控制。使用UDP的应用:域名系统 (DNS);视频流;IP语音(VoIP)。

33、三次握手,四次挥手

1.源端口和目的端口,各占两个字节,分别写入源端口和目的端口;

2.序号,占4个字节,TCP连接中传送的字节流中的每个字节 都按顺序编号,例如,一段报文的序号字段值是101,携带的数据共有100字段,则下一段报文(如果存在下一个报文)的数据序号就应该从201开始;

3.确认号,占4个字节,是期望收到对方下一个报文的第一个数据字节的序号。例如B收到了A发送过来的报文,其序列号是201,而数据长度是300字节,这表明B正确收到了A发送的到序号500为止的数据。所以,B希望收到A的下一个数据序号是501,于是B在向A发送的确认报文中把确认号置为501;

4.数据偏移,占4位,它指出TCP报文的数据距离TCP报文段的起始位置有多远;

5.保留,占6位,保留今后使用,目前应该都为0;

6.紧急URG,URG=1时,证明紧急指针字段有效,告诉系统此报文段中有紧急数据;

7.确认ACK,仅当ACK=1时,确认号字段才有效,TCP规定,在连接建立后所有报文的传输都必须把ACK置为1;

8.推送PSH,当两个应用进程进行交互式通行时,一端的应用进程希望在键入一个命令后能够立即得到对方的响应,这是就置PSH=1;

9.重置(复位)RST,RST=1,表明TCP连接中出现严重差错,必须释放连接,然后再重新连接;

10.同步SYN,在建立连接时用于同步信号。当SYN=1,ACK=0时表明是连接请求报文,若同意连接,则响应报文中会使SYN=1,ACK=1;

11.终止FIN,用于释放连接。当FIN=1时,表明此报文的发送方的数据已经发送完毕,并且要求释放连接;

12.窗口,占2字节,指的是通知接收方,发送本报文你需要有多大的空间来接受;

13.校验和,占2字节,检验首部和数据这两部分;

14.紧急指针,占2字节,指出本报文段的紧急数据的字节数;

15.选项 ,长度可变,定义一些其他的可选参数。

1.第一次握手:客户A发送位码SYN=1,随机产生seq=x 的数据包到服务器B,服务器B有SYN=1知道,客户A要求建立联机,此时客户A进入SYN_SENT状态,等待服务器B确认;

2.第二次握手:服务器B收到确认请求后要确认联机信息,向客户A发送ack=x+1(即seq+1),seq=y,ACK=1,SYN=1,此时服务器B相当于为客户A做确认的同时发送了一个自己的seq需要客户A做确认,服务器B进入SYN_RECV状态;

3.第三次握手:客户A收到后检查ack是否正确(即自己发送的seq+1)并确认ACK=1,若正确,客户A再向服务器B发送ACK=1,seq=x+1,ack=y+1,服务器B收到后确认seq(是否等于自己发送的ack)ack(是否是自己发送的 seq+1)并且ACK=1则连接建立成功。此时服务器进入ESTABLISHED状态,意味着 可以开始数据传输了。

1.客户机主动请求关闭连接,向服务器发送一个FIN=1(用来关闭客户机到服务器的数据传送),seq=u(随机序列号),客户机进入FIN_WAIT1状态;

2.服务器收到该报文后回应一个报文,ACK=1,ack=u+1,seq=v,服务器进入CLOSE_WAIT状态,客户机收到服务器回复后进入FIN_WAIT2状态;

3.服务器查看自身是否有未发送或者待发送的数据,若无,服务器被动关闭连接,向客户机发送FIN报文,FIN=1,ACK=1,seq=w,ack=u+1。若有待传输的数据,执行完后再发送FIN报文;

4.客户机收到服务器的FIN报文后,随机发送ACK报文确认,ACK=1,ack=w+1,客户机进入TIME_WAIT状态(用于可靠地终止TCP连接,保证让迟来的TCP报文段有足够短的时间被 识别并丢弃),待两个MSL(报文最大生存时间,保证本次连接的所有数据从网络中消失,避免出现粘包现像)后进入CLOSED状态,服务器收到ACK=1后进入CLOSED状态。

34、事务和数据库连接池的关系

35、你怎么理解线程安全

36、servlet是什么时候被加载的

默认的servlet被第一次调用时候进行加载,也可以经过配置load-on-startup

37、流的分类:

			字节流和字符流(按照传输的流的字节数)

			输入输出(按照流向)

			缓冲流、转换流属于包装流,包装流对应的是另一种基本流

38、for循环和foreach循环

当遍历数组结构的集合时用for或者foreach都行

     (1、在固定长度或者长度不需要计算的时候for循环效率高于foreach;2、在不确定长度或者计算长度有损性能的时候用foreach比较方便--可以自己测试一下),

       当遍历链表结构的集合时一定不要用for循环。

39、有没有登过网页版微信,问我用手机扫二维码登录是怎么实现的?

浏览器获得一个唯一的、临时的uid,通过长连接等待客户端扫描带有此uid的二维码后,从长连接中获得客户端上报给服务器的帐号信息进行展示。并在客户端点击确认后,获得服务器授信的令牌,进行随后的信息交互过程。 在超时、网络断开、其他设备上登录后,此前获得的令牌或丢失、或失效,对授权过程形成有效的安全防护。

40、多线程,线程与进程有什么区别?结合内存说下

41、spring,IOC和AOP的原理,以及它的应用和实现?

42、Spring相关,要把一个组件注入到Spring中该怎么做?

43、collection的理解,选择一种说下底层实现?

44、JVM内存模型,JVM加载原理。

JVM内存模型

Java代码是运行在Java虚拟机(JVM)上的,Java虚拟机通过解释执行(解释器)或编译执行(编译器)来完成。

Java内存模型分为5个部分:方法区(Method Area),Java堆(Heap),Java栈(VM Stack),本地方法栈(Native Method Stack),程序计数器(PC 寄存器)

(图片来源:http://gityuan.com/images/jvm/jvm_memory_1.png)

线程共享区:

方法区(Method Area):方法区是各个线程共享的区域,存放类信息,常量,静态常量,编译器编译后的代码等信息。

Java堆(Heap):Java堆也是线程共享区域,类的实例存放在这里,一个系统会产生很多Java实例,因此Java堆的空间是最大的,如果Java堆的空间不足,就会抛出OutOfMemoryError异常。

线程私有区:

Java栈(VM Stack):线程私有区域,生命周期与线程相同,一个线程对应一个Java栈,每执行一个方法就会向栈里压一个元素,这个元素叫“栈帧”,栈帧中包含了方法中保存了该方法调用的参数、局部变量和返回地址等信息,如果栈空间不足了就会抛出StackOverflowError异常。

本地方法栈(Native Method Stack):和Java栈类似,本地方法栈是用来执行本地方法的,存放的方法调用本地方法接口,最终调用本地方法库,实现与操作系统,硬件交互的目的。

程序计数器:这里对应的类以及加载,实例对象,方法,静态变量去了该去的地方,那么问题来了,程序该怎么执行,哪个方法先执行,哪个方法后执行,这些指令执行的顺序就是PC寄存器在管,它的作用就是控制程序指令的执行顺序。

类加载机制

编写的java代码会通过编译器编译成字节编码的.class文件,再把字节编码加载到JVM中,映射到内存的各个区域中,程序就可以在内存中运行了。

类加载流程

1,加载

加载是类装载的第一步,内存中生成一个代表这个类的java.lang.class对象,通过class文件的路径读取到二进制流,并解析二进制里的元数据(类型,常量等),作为方法区这个类的各种数据量的入口;这里的不一定从class文件获取,这里既可以从ZIP包(jar,war)包中获取,也在运行时动态生成(jsp转换成class文件,动态代理生成)。

2,连接

连接又可分为验证,准备,解析。

2.1,验证

验证主要是判断class文件的合法性,对版本号进行验证(例如如果使用java1.8编译后的class文件要再java1.6虚拟机上运行),还会对元数据,字节编码等进行验证,确保class文件里的字节流信息符合当前虚拟机的要求,不会危害虚拟机的安全。

2.2,准备

准备主要是分配内存,为变量分配初始值,即在方法区中分配这些变量所使用的内存空间,例如:

public static int i = 1;

在准备阶段i的值会被初始化为0,后面的类的初始化阶段才会赋值为1;

public static final int i = 1;

对应常量(static final)i,在准备阶段就会被赋值1;

2.3,解析

解析就是把代码中的符号引用替换为直接引用;例如某个类继承了java.lang.Object,原来的符号引用记录的是“java.lang.Object”,并不是java.lang,Object对象,直接引用就是找出对应的java.lang.Object对应的内存地址,建立直接引用关系;

3,初始化

初始化的过程包括执行类构造器方法,static变量赋值语句,static{}代码块,如果是一个子类进行初始化会先对其父类进行初始化,保证其父类在子类之前进行初始化;所以其实在java中初始化一个类,那么必然是先初始化java.lang.Object,因为所有的java类都继承自java.lang.Object。

以下几种情况不会执行类初始化:

  • 通过子类引用父类的静态字段,只会触发父类的初始化,而不会触发子类的初始化。
  • 定义对象数组,不会触发该类的初始化。
  • 常量在编译期间会存入调用类的常量池中,本质上并没有直接引用定义常量的类,不会触发定义常量所在的类。
  • 通过类名获取Class对象,不会触发类的初始化。
  • 通过Class.forName加载指定类时,如果指定参数initialize为false时,也不会触发类初始化,其实这个参数是告诉虚拟机,是否要对类进行初始化。
  • 通过ClassLoader默认的loadClass方法,也不会触发初始化动作。

类加载器

在JVM中有三中类加载器,BootStrap Classloader(启动Classloader)、Extension Classloader(扩展Classloader)和APP Classloader(应用Classloader);

BootStrap ClassLoader主要加载JVM自身需要的类,这个加载器由C++编写是虚拟机的一部分,负责加载 JAVA_HOME\lib 目录中的,或通过-Xbootclasspath参数指定路径中的,且被虚拟机认可(按文件名识别,如rt.jar)的类。

Extension Classloader是sun.misc.Launcher中的内部类ExtClassLoader,负责加载 JAVA_HOME\lib\ext 目录中的,或通过java.ext.dirs系统变量指定路径中的类库。

APP ClassLoader是sun.misc.Launcher中的内部类AppClassLoader,负责加载用户路径上的类库。

用户也可以通过继承ClassLoader实现自己的类加载器。

双亲委派模式

当一个类加载器接收到类加载的任务时,会首先交给其父类加载器去加载,只有当父类加载器无法加载是其才会自己加载。其好处是可以避免一个类被重复加载。

即使两个类来源于相同的class文件,如果使用的类加载器不同,加载后的对象时完全不同的,这个不同反应在对象的 equals()、isAssignableFrom()、isInstance()等方法的返回结果,也包括了使用 instanceof 关键字对对象所属关系的判定结果。

双亲委派模式的问题

顶层ClassLoader,无法加载底层ClassLoader的类

Java框架(rt.jar)如何加载应用的类?

比如:javax.xml.parsers包中定义了xml解析的类接口

Service Provider Interface SPI 位于rt.jar

即接口在启动ClassLoader中。

而SPI的实现类,在AppLoader。

这样就无法用BootstrapClassLoader去加载SPI的实现类。

解决

JDK中提供了一个方法:

   1:  Thread. setContextClassLoader()

用以解决顶层ClassLoader无法访问底层ClassLoader的类的问题;

基本思想是,在顶层ClassLoader中,传入底层ClassLoader的实例。

45、spring的理解,如何进行bean的配置,用ssh做没做过什么项目?

46、线程中止的原因

stop方法,或者出现异常,正常结束是设置一个标志位,run方法结束就可以结束线程。设置成守护线程就可以。

47、cookie,session的区别

cookie是存储在本地浏览器,而session存储在服务器。

cookie第一次登录后服务器返回一些数据(cookie)给浏览器,然后浏览器保存在本地,当该用户发送第二次请求的时候,就会自动的把上次请求存储的cookie数据自动的携带给服务器,服务器通过浏览器携带的数据就能判断当前用户是哪个了。cookie存储的数据量有限,不同的浏览器有不同的存储大小,但一般不超过4KB。因此使用cookie只能存储一些小量的数据。默认的cookie只能存字符串,而且不支持中文。

session存储在服务器。存储在服务器的数据会更加的安全,不容易被窃取。但存储在服务器也有一定的弊端,就是会占用服务器的资源,但现在服务器已经发展至今,一些session信息还是绰绰有余的。1800s,半个小时。

==============

1.session用来表示用户会话,session对象在服务端维护,一般tomcat设定session生命周期为30分钟,超时将失效,也可以主动设置无效;

2.cookie存放在客户端,可以分为内存cookie和磁盘cookie。内存cookie在浏览器关闭后消失,磁盘cookie超时后消失。当浏览器发送请求时,将自动发送对应cookie信息,前提是请求url满足cookie路径;

3.可以将sessionId存放在cookie中,也可以通过重写url将sessionId拼接在url。因此可以查看浏览器cookie或地址栏url看到sessionId;

4.请求到服务端时,将根据请求中的sessionId查找session,如果可以获取到则返回,否则返回null或者返回新构建的session,老的session依旧存在,请参考API。

联系:session是基于cookie实现的,将session的id号存储在cookie,否则就只能通过url传参。

48、collection和collections区别

collection是集合的接口,list,set会继承这个接口,collections是对集合类一些方法的封装(集合的工具类),比如这里边有一个binarySearch(),这个方法使用的前提,必须是有序的,因为是折半查找。

49、如何实现克隆?

如果一个A类中含有B类对象,那么这两个类都需要实现Coloneable接口。

1). 实现 Cloneable 接口并重写 Object 类中的 clone()方法;

2). 实现 Serializable 接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆,代码如下

浅克隆:实现Object类的clone方法,对于引用数据类型来说只会指向引用,并不会重新开辟内存空间

深客隆:实现Cloneable接口,重写Object的Clone方法,深克隆对于引用数据类型也会重新开辟内存空间进行存储,是完全相同的两个对象。

50、sleep和wait区别

sleep()是thread类的方法,不释放锁资源,等休眠结束就可以进入运行状态。sleep必须传参,时间结束可以唤醒

wait()是object类方法,释放锁资源,需要notify来进行唤醒,然后进入就绪状态,争夺cpu。wait也可以有参,参数结束可以自己唤醒,wait()必须放在同步代码块中,否则会出错。

两者都需要抛出异常(interruptedException)。

51、servlet和cgi的区别

Servlet 与 CGI 的比较:servlet的可移植性好

和CGI程序一样,Servlet可以响应用户的指令(提交一个FORM等等),也可以象CGI程序一样,收集用户表单的信息并给予动态反馈(简单的注册信息录入和检查错误)。

然而,Servlet的机制并不仅仅是这样简单的与用户表单进行交互。传统技术中,动态的网页建立和显示都是通过CGI来实现的,但是,有了Servlet,您可以大胆的放弃所有CGI(perl?php?甚至asp!),利用Servlet代替CGI,进行程序编写。

对比一:当用户浏览器发出一个Http/CGI的请求,或者说调用一个CGI程序的时候,服务器端就要新启用一个进程 (而且是每次都要调用),调用CGI程序越多(特别是访问量高的时候),就要消耗系统越多的处理时间,只剩下越来越少的系统资源,对于用户来说,只能是漫长的等待服务器端的返回页面了,这对于电子商务激烈发展的今天来说,不能不说是一种技术上的遗憾。

而Servlet充分发挥了服务器端的资源并高效的利用。每次调用Servlet时并不是新启用一个进程 (多线程),而是在一个Web服务器的进程敏感词享和分离线程,而线程最大的好处在于可以共享一个数据源,使系统资源被有效利用。

对比二:传统的CGI程序,不具备平台无关性特征,系统环境发生变化,CGI程序就要瘫痪,而Servlet具备Java的平台无关性,在系统开发过程中保持了系统的可扩展性、高效性。

对比三:传统技术中,一般大都为二层的系统架构,即Web服务器+数据库服务器,导致网站访问量大的时候,无法克服CGI程序与数据库建立连接时速度慢的瓶颈,从而死机、数据库死锁现象频繁发生。而我们的Servlet有连接池的概念,它可以利用多线程的优点,在系统缓存中事先建立好若干与数据库的连接,到时候若想和数据库打交道可以随时跟系统"要"一个连接即可,反应速度可想而知。

52、创建对象的四种方式

new,克隆,反射,反序列化

53、如何保证懒汉式只有一个实例

加上同步关键字,构造器私有化

54、sqlSessionFactory是单例的

55、Mybatis中使用配置时,是有一个默认的,如果忘记在配置文件中写的话,会自动是用默认的

56、mybatis执行效率高于hibernate,因为中间省略了好多互相映射的关系

57、拦截器和过滤器

拦截器是基于springMVC容器,拦截器可以调用IOC容器中的各种依赖,java反射机制,拦截器可多次调用

过滤器是基于servlet容器,过滤器可以修改request,而拦截器不能,函数的回调,只在服务器启动的时候加载一次。

过滤器只能在请求的前后使用,而拦截器可以详细到每个方法

58、JVM的垃圾回收

两个最基本的java回收算法:复制算法和标记清理算法

复制算法:两个区域A和B,初始对象在A,继续存活的对象被转移到B。此为新生代最常用的算法

标记清理:一块区域,标记可达对象(可达性分析),然后回收不可达对象,会出现碎片,那么引出

标记-整理算法:多了碎片整理,整理出更大的内存放更大的对象

两个概念:新生代和年老代

新生代:初始对象,生命周期短的

永久代:长时间存在的对象

整个java的垃圾回收是新生代和年老代的协作,这种叫做分代回收。

P.S:Serial New收集器是针对新生代的收集器,采用的是复制算法

Parallel New(并行)收集器,新生代采用复制算法,老年代采用标记整理

Parallel Scavenge(并行)收集器,针对新生代,采用复制收集算法

Serial Old(串行)收集器,新生代采用复制,老年代采用标记整理

Parallel Old(并行)收集器,针对老年代,标记整理

CMS收集器,基于标记清理

G1收集器:整体上是基于标记 整理 ,局部采用复制

综上:新生代基本采用复制算法,老年代采用标记整理算法。cms采用标记清理。

59、HashMap 的长度为什么是2的幂次方

为了能让 HashMap 存取高效,尽量较少碰撞,也就是要尽量把数据分配均匀,每个链表/红黑树长度大致相同。这个实现就是把数据存到哪个链表/红黑树中的算法。

这个算法应该如何设计呢?

我们首先可能会想到采用%取余的操作来实现。但是,重点来了:“取余(%)操作中如果除数是2的幂次则等价于与其除数减一的与(&)操作(也就是说 hash%length==hash&(length-1)的前提是 length 是2的 n 次方;)。” 并且 采用二进制位操作 &,相对于%能够提高运算效率,这就解释了 HashMap 的长度为什么是2的幂次方。

60、HashMap与HashTable的底层原理

HashMap使用迭代器进行遍历(快速失败),而HashTable使用Enumeration(安全失败)

HashMap采用的是数组+链表+红黑树的形式。

数组是可以扩容的,链表也是转化为红黑树的,这2种方式都可以承载更多的数据。

用户可以设置的参数:初始总容量默认16,默认的加载因子0.75

初始的数组个数默认是16 容量X加载因子=阈值

一旦目前容量超过该阈值,则执行扩容操作。

什么时候扩容?

  • 1 当前容量超过阈值
  • 2 当链表中元素个数超过默认设定(8个),当数组的大小还未超过64的时候,此时进行数组的扩容,如果超过则将链表转化成红黑树

什么时候链表转化为红黑树?(上面已经提到了)

  • 当数组大小已经超过64并且链表中的元素个数超过默认设定(8个)时,将链表转化为红黑树

目前形象的表示数组中的一个元素称为一个桶

JDK1.8之前

JDK1.8 之前 HashMap 由 数组+链表 组成的(“链表散列” 即数组和链表的结合体),数组是 HashMap 的主体,链表则是主要为了解决哈希冲突而存在的(HashMap 采用 “拉链法也就是链地址法” 解决冲突),如果定位到的数组位置不含链表(当前 entry 的 next 指向 null ),那么对于查找,添加等操作很快,仅需一次寻址即可;如果定位到的数组包含链表,对于添加操作,其时间复杂度依然为 O(1),因为最新的 Entry 会插入链表头部,即需要简单改变引用链即可,而对于查找操作来讲,此时就需要遍历链表,然后通过 key 对象的 equals 方法逐一比对查找.

所谓 “拉链法” 就是将链表和数组相结合。也就是说创建一个链表数组,数组中每一格就是一个链表。若遇到哈希冲突,则将冲突的值加到链表中即可。

JDK1.8之后

相比于之前的版本, JDK1.8之后在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8)时,将链表转化为红黑树,以减少搜索时间。

TreeMap、TreeSet以及JDK1.8之后的HashMap底层都用到了红黑树。红黑树就是为了解决二叉查找树的缺陷,因为二叉查找树在某些情况下会退化成一个线性结构。

61、利用反射创建类的三种方式

1、直接使用构造器进行new,

2、知道的指定类的对象obj,obj.getclass(),

类名.class

class.forName();

62、自定义一个java.lang.String类,这个类是否可以被类加载器加载?为什么

不可以,因为jvm的类加载具有双亲委派机制,所谓双亲委派就是对于一个要加载的class时,首先把该class的查询和加载优先委派给父类加载器,而他的父类加载器是启动类加载器,启动类加载器是用来加载JAVA的核心库,比如String类,System类。而类加载器的缓存机制是所有加载过的类的实例存在起来,当调用某个实例时,先从缓冲区查找,若缓冲区不存在,才会加载,所以自定义的java.lang.String的类不会去加载。

不能以java。lang开头的名可以被自己写的类加载器进行加载。

63、什么是happens-before原则?

从JDK5开始,提出了happens-before的概念,通过这个概念来阐述操作之间的内存可见性。如果一个操作执行的结果需要对另一个操作可见,那么这两个操作之间必须存在happens-before关系。这里提到的两个操作既可以是在一个线程之内,也可以是在不同线程之间。

如果一个操作happens-before(之前发生)另一个操作,那么第一个操作的执行结果将对第二个操作可见,而且第一个操作的执行顺序排在第二个操作之前。

两个操作之间存在happens-before关系,并不意味着一定要按照happens-before原则制定的顺序来执行。如果重排序之后的执行结果与按照happens-before关系来执行的结果一致,那么这种重排序并不非法。

与程序员相关的happens-before原则

程序次序规则:一个线程内,按照代码顺序,书写在前面的操作先行发生于书写在后面的操作;

锁定规则:一个unLock操作先行发生于后面对同一个锁额lock操作;

volatile变量规则:对一个变量的写操作先行发生于后面对这个变量的读操作;

传递规则:如果操作A先行发生于操作B,而操作B又先行发生于操作C,则可以得出操作A先行发生于操作C;

线程启动规则:Thread对象的start()方法先行发生于此线程的每个一个动作;

线程中断规则:对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生;

线程终结规则:线程中所有的操作都先行发生于线程的终止检测,我们可以通过Thread.join()方法结束、Thread.isAlive()的返回值手段检测到线程已经终止执行;

对象终结规则:一个对象的初始化完成先行发生于他的finalize()方法的开始;

64、请你介绍一下Syncronized锁,如果用这个关键字修饰一个静态方法,锁住了什么?如果修饰成员方法,锁住了什么?

synchronized修饰静态方法以及同步代码块的synchronized (类.class)用法锁的是类,线程想要执行对应同步代码,需要获得类锁。

synchronized修饰成员方法,线程获取的是当前调用该方法的对象实例的对象锁

65、并行并发

并发(Concurrent),在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行。,并发需要等待,只有一个cpu进行处理

并行(Parallel),当系统有一个以上CPU时,当一个CPU执行一个进程时,另一个CPU可以执行另一个进程,两个进程互不抢占CPU资源,可以同时进行,这种方式我们称之为并行(Parallel)。两个cpu互相不需要抢占,可以同时进行计算。

66、 请说说快速失败(fail-fast)和安全失败(fail-safe)的区别?

Iterator的安全失败是基于对底层集合做拷贝,因此,它不受源集合上修改的影响。java.util包下面的所有的集合类都是快速失败的,而java.util.concurrent包下面的所有的类都是安全失败的。快速失败的迭代器会抛出ConcurrentModificationException异常,而安全失败的迭代器永远不会抛出这样的异常。

67、同步和异步的区别

同步:

同步的思想是:所有的操作都做完,才返回给用户。这样用户在线等待的时间太长,给用户一种卡死了的感觉(就是系统迁移中,点击了迁移,界面就不动了,但是程序还在执行,卡死了的感觉)。这种情况下,用户不能关闭界面,如果关闭了,即迁移程序就中断了。

异步:

将用户请求放入消息队列,并反馈给用户,系统迁移程序已经启动,你可以关闭浏览器了。然后程序再慢慢地去写入数据库去。这就是异步。但是用户没有卡死的感觉,会告诉你,你的请求系统已经响应了。你可以关闭界面了。

同步,是所有的操作都做完,才返回给用户结果。即写完数据库之后,在相应用户,用户体验不好。

异步,不用等所有操作等做完,就相应用户请求。即先相应用户请求,然后慢慢去写数据库,用户体验较好。

68、解释什么是io,nio,aio

 一、缓冲区(Buffer):在 Java NIO 中负责数据的存取。缓冲区就是数组。用于存储不同数据类型的数据
 * 
 * 根据数据类型不同(boolean 除外),提供了相应类型的缓冲区:
 * ByteBuffer
 * CharBuffer
 * ShortBuffer
 * IntBuffer
 * LongBuffer
 * FloatBuffer
 * DoubleBuffer
 * 
 * 上述缓冲区的管理方式几乎一致,通过 allocate() 获取缓冲区
 * 
 * 二、缓冲区存取数据的两个核心方法:
 * put() : 存入数据到缓冲区中
 * get() : 获取缓冲区中的数据
 * 
 * 三、缓冲区中的四个核心属性:
 * capacity : 容量,表示缓冲区中最大存储数据的容量。一旦声明不能改变。
 * limit : 界限,表示缓冲区中可以操作数据的大小。(limit 后数据不能进行读写)
 * position : 位置,表示缓冲区中正在操作数据的位置。
 * 
 * mark : 标记,表示记录当前 position 的位置。可以通过 reset() 恢复到 mark 的位置
 * 
 * 0 <= mark <= position <= limit <= capacity
 * 
 * 四、直接缓冲区与非直接缓冲区:
 * 非直接缓冲区:通过 allocate() 方法分配缓冲区,将缓冲区建立在 JVM 的内存中
 * 直接缓冲区:通过 allocateDirect() 方法分配直接缓冲区,将缓冲区建立在物理内存中。可以提高效率

 一、通道(Channel):用于源节点与目标节点的连接。在 Java NIO 中负责缓冲区中数据的传输。Channel 本身不存储数据,因此需要配合缓冲区进行传输。
 * 
 * 二、通道的主要实现类
 * 	java.nio.channels.Channel 接口:
 * 		|--FileChannel
 * 		|--SocketChannel
 * 		|--ServerSocketChannel
 * 		|--DatagramChannel
 * 
 * 三、获取通道
 * 1. Java 针对支持通道的类提供了 getChannel() 方法
 * 		本地 IO:
 * 		FileInputStream/FileOutputStream
 * 		RandomAccessFile
 * 
 * 		网络IO:
 * 		Socket
 * 		ServerSocket
 * 		DatagramSocket
 * 		
 * 2. 在 JDK 1.7 中的 NIO.2 针对各个通道提供了静态方法 open()
 * 3. 在 JDK 1.7 中的 NIO.2 的 Files 工具类的 newByteChannel()
 * 
 * 四、通道之间的数据传输
 * transferFrom()
 * transferTo()
 * 
 * 五、分散(Scatter)与聚集(Gather)
 * 分散读取(Scattering Reads):将通道中的数据分散到多个缓冲区中
 * 聚集写入(Gathering Writes):将多个缓冲区中的数据聚集到通道中
 * 
 * 六、字符集:Charset
 * 编码:字符串 -> 字节数组
 * 解码:字节数组  -> 字符串
 
 
 
 
  * 一、使用 NIO 完成网络通信的三个核心:
 * 
 * 1. 通道(Channel):负责连接
 * 		
 * 	   java.nio.channels.Channel 接口:
 * 			|--SelectableChannel
 * 				|--SocketChannel
 * 				|--ServerSocketChannel
 * 				|--DatagramChannel
 * 
 * 				|--Pipe.SinkChannel
 * 				|--Pipe.SourceChannel
 * 
 * 2. 缓冲区(Buffer):负责数据的存取
 * 
 * 3. 选择器(Selector):是 SelectableChannel 的多路复用器。用于监控 SelectableChannel 的 IO 状况

面向Stream和面向Buffer

Java NIO和IO之间最大的区别是IO是面向流(Stream)的,NIO是面向块(buffer)的,所以,这意味着什么?

面向流意味着从流中一次可以读取一个或多个字节,拿到读取的这些做什么你说了算,这里没有任何缓存(这里指的是使用流没有任何缓存,接收或者发送的数据是缓存到操作系统中的,流就像一根水管从操作系统的缓存中读取数据)而且只能顺序从流中读取数据,如果需要跳过一些字节或者再读取已经读过的字节,你必须将从流中读取的数据先缓存起来。

面向块的处理方式有些不同,数据是先被 读/写到buffer中的,根据需要你可以控制读取什么位置的数据。这在处理的过程中给用户多了一些灵活性,然而,你需要额外做的工作是检查你需要的数据是否已经全部到了buffer中,你还需要保证当有更多的数据进入buffer中时,buffer中未处理的数据不会被覆盖

阻塞IO和非阻塞IO

所有的Java IO流都是阻塞的,这意味着,当一条线程执行read()或者write()方法时,这条线程会一直阻塞知道读取到了一些数据或者要写出去的数据已经全部写出,在这期间这条线程不能做任何其他的事情

java NIO的非阻塞模式(Java NIO有阻塞模式和非阻塞模式,阻塞模式的NIO除了使用Buffer存储数据外和IO基本没有区别)允许一条线程从channel中读取数据,通过返回值来判断buffer中是否有数据,如果没有数据,NIO不会阻塞,因为不阻塞这条线程就可以去做其他的事情,过一段时间再回来判断一下有没有数据

NIO的写也是一样的,一条线程将buffer中的数据写入channel,它不会等待数据全部写完才会返回,而是调用完write()方法就会继续向下执行

Selectors

Java NIO的selectors允许一条线程去监控多个channels的输入,你可以向一个selector上注册多个channel,然后调用selector的select()方法判断是否有新的连接进来或者已经在selector上注册时channel是否有数据进入。selector的机制让一个线程管理多个channel变得简单。

NIO和IO对应用的设计有何影响

选择使用NIO还是IO做你的IO工具对应用主要有以下几个方面的影响

1、使用IO和NIO的API是不同的(废话)

2、处理数据的方式

3、处理数据所用到的线程数

69、TreeMap的底层实现(红黑树)

TreeMap 的实现就是红黑树数据结构,也就说是一棵自平衡的排序二叉树,这样就可以保证当需要快速检索指定节点。

红黑树的插入、删除、遍历时间复杂度都为O(lgN),所以性能上低于哈希表。但是哈希表无法提供键值对的有序输出,红黑树因为是排序插入的,可以按照键的值的大小有序输出。红黑树性质:

性质1:每个节点要么是红色,要么是黑色。

性质2:根节点永远是黑色的。

性质3:所有的叶节点都是空节点(即 null),并且是黑色的。

性质4:每个红色节点的两个子节点都是黑色。(从每个叶子到根的路径上不会有两个连续的红色节点)

性质5:从任一节点到其子树中每个叶子节点的路径都包含相同数量的黑色节点。

70、九大内置对象

request:每当客户端请求页面时,JSP引擎将创建一个新对象来表示该请求。

response:就像服务器创建request对象一样,它还创建一个对象来表示对客户端的响应。

out:out隐式对象是javax.servlet.jsp.JspWriter对象的一个实例,用于在响应中发送内容。

session:session对象用于跟踪客户端请求之间的客户端会话。

application:对象是JSP页面在其整个生命周期中的表示。 当JSP页面被初始化时,将创建此对象,并且在JSP页面被jspDestroy()方法删除时application对象也将被删除。

通过向application对象添加属性值,可以确保组成Web应用程序的所有JSP文件都可以访问它。

config:对象是javax.servlet.ServletConfig的实例化,是生成的servlet的ServletConfig对象周围的直接包装。

pageContext:pageContext对象用于表示整个JSP页面。

page:对象是对该页面实例的实际引用。可以认为它是表示整个JSP页面的对象。

exception:对错误的相应,他只能用于error.jsp

71、四个域对象

作用域:request,session,application,page

作用域对象:request、session、application和pageContext

72、MySQL几种锁

MyISAM:

myisam只支持表级锁,用户在操作myisam表时,select,update,delete,insert语句都会给表自动加锁,如果加锁以后的表满足insert并发的情况下,可以在表的尾部插入新的数据。也可以通过lock table命令来锁表,这样操作主要是可以模仿事务,但是消耗非常大,一般只在实验演示中使用。

InnoDB :

Innodb支持事务和行级锁,是innodb的最大特色。

事务的ACID属性:atomicity,consistent,isolation,durable。

并发事务带来的几个问题:更新丢失,脏读,不可重复读,幻读。

事务隔离级别:未提交读(Read uncommitted),已提交读(Read committed),可重复读(Repeatable read),可序列化(Serializable)

InnoDb:引入了行锁

myisam:要锁住这行数据的时候,就相当于锁住了整张表

73、请说出你知道的线程同步的方法及注意事项;

sleep(抛出异常),wait(释放锁),notify(随机唤醒),notifyAll(唤醒所有处于等待的线程,让他们去竞争)

74、hashset内部是如何工作的

HashSet 的内部采用 HashMap来实现。由于 Map 需要 key 和 value,所以HashSet中所有 key 的都有一个默认 value。类似于 HashMap,HashSet 不允许重复的 key,只允许有一个null key,意思就是 HashSet 中只允许存储一个 null 对象。

75、Spring 框架中 BeanFactory 和 ApplicationContext 有什么联系?

beanFactory是bean创建,无法支持支持spring插件

ApplicationContext是BeanFactory的子类,

1、MessageSource,提供国际化的消息访问

2、资源访问(如URL和文件)

3、事件传播

4、载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层。

BeanFactroy初始化容器时,并未初始化Bean,直到第一次在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化(延迟加载),这样的话,我们就不能在初始化容器时发现一些存在的Spring的配置问题。而ApplicationContext则相反,它是在容器启动时,就一次性创建了所有的Bean。这样,在容器启动时,我们就可以发现Spring中存在的配置错误。

76、你对事务的理解

事务具有四个特性

原子性:事务被作为一个整体执行,要么全部执行成功,要么全部回滚(由DBMS的事务管理子系统来实现)

持久性:已被提交事务的修改在数据库中应该永久的保存在数据库中。(恢复管理子系统)

一致性:事务确保 数据库的状态从一个一致状态,一致状态的含义是数据库中的数据应该满足完整性约束(由DBMS的恢复管理子系统实现的)

隔离性:多个事务的并发执行时,一个事务的执行不应该影响其他事务的执行(由DBMS的并发控制子系统实现)

77、乐观锁和悲观锁

悲观锁:总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁(共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程)。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。Java中synchronized和ReentrantLock等独占锁就是悲观锁思想的实现。

乐观锁;总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号机制和CAS算法实现。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库提供的类似于write_condition机制,其实都是提供的乐观锁。在Java中java.util.concurrent.atomic包下面的原子变量类就是使用了乐观锁的一种实现方式CAS实现的。

在实际生产环境里边,如果并发量不大且不允许脏读,可以使用悲观锁解决并发问题;但如果系统的并发非常大的话,悲观锁定会带来非常大的性能问题,所以我们就要选择乐观锁定的方法.

78、事务中的隔离级别

Read Uncommitted(读取未提交内容,简称RU)

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

Read Committed(读取提交内容,简称RC)

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

Repeatable Read(可重复读,简称RR)

这是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行,但是有个新问题,幻读 (Phantom Read),就是会读取到别的事务新插入的数据,也称之为幻影数据。不可重复读着重的是读取到别的事务修改的数据,而幻读着重的是读取到别的事务插入的数据。

Serializable(可串行化)

这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之就是读加读锁写加写锁。在这个级别,可能导致大量的超时现象和锁竞争,并发粒度最低。

79、请简单说明一下什么是迭代器

Iterator提供了统一遍历操作集合元素的统一接口, Collection接口实现Iterable接口,

每个集合都通过实现Iterable接口中iterator()方法返回Iterator接口的实例, 然后对集合的元素进行迭代操作.

有一点需要注意的是:在迭代元素的时候不能通过集合的方法删除元素, 否则会抛出ConcurrentModificationException 异常. 但是可以通过Iterator接口中的remove()方法进行删除.

注意:在迭代器中只能使用迭代器的remove方法进行迭代删除。

80、请解释一下ArrayList是否会越界?

arrayList是实现了基于动态数组的数据结构,所以一般不会越界,但是在并发add操作的时候可能会进行越界

81、请你解释一下什么是线程池(thread pool)?

在面向对象编程中,创建和销毁对象是很费时间的,因为创建一个对象要获取内存资源或者其它更多资源。在Java中更是如此,虚拟机将试图跟踪每一个对象,以便能够在对象销毁后进行垃圾回收。所以提高服务程序效率的一个手段就是尽可能减少创建和销毁对象的次数,特别是一些很耗资源的对象创建和销毁,这就是”池化资源”技术产生的原因。线程池顾名思义就是事先创建若干个可执行的线程放入一个池(容器)中,需要的时候从池中获取线程不用自行创建,使用完毕不需要销毁线程而是放回池中,从而减少创建和销毁线程对象的开销。

Java 5+中的Executor接口定义一个执行线程的工具。它的子类型即线程池接口是ExecutorService。要配置一个线程池是比较复杂的,尤其是对于线程池的原理不是很清楚的情况下,因此在工具类Executors面提供了一些静态工厂方法,生成一些常用的线程池,如下所示:

  • newSingleThreadExecutor:创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。
  • newFixedThreadPool:创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。
  • newCachedThreadPool:创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。缓存型池子通常用于执行一些生存期很短的异步型任务
  • newScheduledThreadPool:创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求。
  • newSingleThreadExecutor:创建一个单线程的线程池。此线程池支持定时以及周期性执行任务的需求。

82、http和https

HTTPS和HTTP的区别主要如下:

1、https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。

2、http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。

3、http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。

4、http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。

83、内存屏障/内存栅栏

内存屏障(Memory Barrier,或有时叫做内存栅栏,Memory Fence)是一种CPU指令,用于控制特定条件下的重排序和内存可见性问题。Java编译器也会根据内存屏障的规则禁止重排序。(也就是让一个CPU处理单元中的内存状态对其它处理单元可见的一项技术。)

内存屏障可以被分为以下几种类型:

LoadLoad屏障:对于这样的语句Load1; LoadLoad; Load2,在Load2及后续读取操作要读取的数据被访问前,保证Load1要读取的数据被读取完毕。

StoreStore屏障:对于这样的语句Store1; StoreStore; Store2,在Store2及后续写入操作执行前,保证Store1的写入操作对其它处理器可见。

LoadStore屏障:对于这样的语句Load1; LoadStore; Store2,在Store2及后续写入操作被刷出前,保证Load1要读取的数据被读取完毕。

StoreLoad屏障:对于这样的语句Store1; StoreLoad; Load2,在Load2及后续所有读取操作执行前,保证Store1的写入对所有处理器可见。它的开销是四种屏障中最大的。

在大多数处理器的实现中,这个屏障是个万能屏障,兼具其它三种内存屏障的功能。

内存屏障阻碍了CPU采用优化技术来降低内存操作延迟,必须考虑因此带来的性能损失。为了达到最佳性能,最好是把要解决的问题模块化,这样处理器可以按单元执行任务,然后在任务单元的边界放上所有需要的内存屏障。采用这个方法可以让处理器不受限的执行一个任务单元。合理的内存屏障组合还有一个好处是:缓冲区在第一次被刷后开销会减少,因为再填充改缓冲区不需要额外工作了。

84、资源死锁的四个必要条件:

死锁并不仅仅发生在资源上,资源死锁只是一种。

资源死锁的四个必要条件:

(1)互斥条件。每个资源要么已经分配给了一个进程,要么就是可用的。

(2)占有和等待条件。已经得到了某个资源的进程可以再请求新的资源。

(3)不可抢占条件。已经分配给一个进程的资源不能被抢占,只能由占有它的进程显式地释放。

(4)环路等待条件。死锁发生时,系统中一定有由两个或以上的进程组成的一条环路,该环路中的每个进程都在等待着下一个进程所占有的资源。

85、request.getSession(true|false)

true是代表有的话直接取,没有的创建

session有的话去拿,没有的话返回null

86、Mysql的存储引擎

  1. InnoDB

默认使用的引擎是innodb。支持行级锁,主码会使用聚簇索引,支持外码的完整性约束,支持事务。

支持B+树索引(尽管语法中我们看到BTREE,但实际上就是B+树,而不是B树)

不支持哈希索引

  1. MyISAM

不支持事务,提供表级锁

支持B+树索引

不支持哈希索引

3.Memory

在内存中创建表,速度最快,提供表级锁,但数据库重启后数据会丢失

支持B+树索引

支持哈希索引

87、webservice

一、webservice三要素:

WSDL(web服务描述语言)、SOAP(简单对象访问协议)、UDDI(目录服务)

二、实现原理:

webservice定义:(http+XML)

webservice一种使用http传输SOAP协议数据的远程调用技术

WSDL作用:

webservice服务端的使用说明书

SOAP作用:

约束XML标签

UDDI作用:

提供webservice服务端的搜索和注册功能

88、会话跟踪

为什么?

浏览器与服务器之间的通信是通过HTTP协议进行通信的,而HTTP协议是”无状态”的协议,它不能保存客户的信息,即一次响应完成之后连接就断开了,下一次的请求需要重新连接,这样就需要判断是否是同一个用户,所以才应会话跟踪技术来实现这种要求

a) URL重写:

URL(统一资源定位符)是Web上特定页面的地址,URL地址重写的原理是将该用户Session的id信息重写 到URL地址中,以便在服务器端进行识别不同的用户。URL重写能够在客户端停用cookies或者不支持cookies的时候仍然能够发挥作用。

b) 隐藏表单域:

将会话ID添加到HTML表单元素中提交到服务器,此表单元素并不在客户端显示,浏览时看不到,源代码中有。

c) Cookie:

Cookie是Web服务器发送给客户端的一小段信息,客户端请求时可以读取该信息发送到服务器端,进而进行用户的识别。对于客户端的每次请求,服务器都会将Cookie发送到客户端,在客户端可以进行保存,以便下次使用。 服务器创建保存于浏览器端,不可跨域名性,大小及数量有限。客户端可以采用两种方式来保存这个Cookie对象,一种方式是 保存在 客户端内存中,称为临时Cookie,浏览器关闭后 这个Cookie对象将消失。另外一种方式是保存在 客户机的磁盘上,称为永久Cookie。以后客户端只要访问该网站,就会将这个Cookie再次发送到服务器上,前提是 这个Cookie在有效期内。 这样就实现了对客户的跟踪。

Cookie是可以被禁止的。

d) session:

每一个用户都有一个不同的session,各个用户之间是不能共享的,是每个用户所独享的,在session中可以存放信息。 保存在服务器端。需要解决多台服务器间共享问题。如果Session内容过于复杂,当大量客户访问服务器时可能会导致内存溢出。因此,Session里的信息应该尽量精简。

在服务器端会创建一个session对象,产生一个sessionID来标识这个session对象,然后将这个sessionID放入到Cookie中发送到客户端,下一次访问时,sessionID会发送到服务器,在服务器端进行识别不同的用户。

Session是依赖Cookie的,如果Cookie被禁用,那么session也将失效。

89、HTTP协议与TCP/IP协议的关系

HTTP的长连接和短连接本质上是TCP长连接和短连接。HTTP属于应用层协议,在传输层使用TCP协议,在网络层使用IP协议。 IP协议主要解决网络路由和寻址问题,TCP协议主要解决如何在IP层之上可靠地传递数据包,使得网络上接收端收到发送端所发出的所有包,并且顺序与发送顺序一致。TCP协议是可靠的、面向连接的。

90、如何理解HTTP协议是无状态的

HTTP协议是无状态的,指的是协议对于事务处理没有记忆能力,服务器不知道客户端是什么状态。也就是说,打开一个服务器上的网页和上一次打开这个服务器上的网页之间没有任何联系。HTTP是一个无状态的面向连接的协议,无状态不代表HTTP不能保持TCP连接,更不能代表HTTP使用的是UDP协议(无连接)。

91、什么是http的长连接、短连接?

http的长连接实质上是指Tcp连接,http属于应用层协议,本身就没有长短连接之分,而Tcp属于传输层协议,只有在传输的时候才会有长短连接之分,tcp连接是一个双向的通道,他是可以保持一段时间不去关闭。

Http1.1默认都是长连接,需要设置Connection-header:Keep Alive,只要设置之后就是长连接。使用长连接主要是为了复用,避免客户一直请求去创建tcp连接对象。实现长连接需要客户端和服务端都支持长连接,也就是两者都需要进行设置Connection-header。

解释1

所谓长连接指建立SOCKET连接后不管是否使用都保持连接,但安全性较差,

所谓短连接指建立SOCKET连接后发送后接收完数据后马上断开连接,一般银行都使用短连接

解释2

长连接就是指在基于tcp的通讯中,一直保持连接,不管当前是否发送或者接收数据。

而短连接就是只有在有数据传输的时候才进行连接,客户-服务器通信/传输数据完毕就关闭连接。

解释3

长连接和短连接这个概念好像只有移动的CMPP协议中提到了,其他的地方没有看到过。

通信方式

各网元之间共有两种连接方式:长连接和短连接。所谓长连接,指在一个TCP连接上可以连续发送多个数据包,在TCP连接保持期间,如果没有数据包发送,需要双方发检测包以维持此连接。短连接是指通信双方有数据交互时,就建立一个TCP连接,数据发送完成后,则断开此TCP连接,即每次TCP连接只完成一对 CMPP消息的发送。

现阶段,要求ISMG之间必须采用长连接的通信方式,建议SP与ISMG之间采用长连接的通信方式。

解释4

短连接:比如http的,只是连接、请求、关闭,过程时间较短,服务器若是一段时间内没有收到请求即可关闭连接。

长连接:有些服务需要长时间连接到服务器,比如CMPP,一般需要自己做在线维持。

对于普通的web应用,用长连接的好处?

长连接的话避免每次都创建tcp连接对象了,因为每次使用的都是一个TCP连接对象。长连接并不是永久连接的,时间长短可以在header中进行设置,如果这个连接没有http请求没有发出的话,那么这个长连接就会被断开。

92、什么是长轮询,短轮询?

长轮询:http 长轮询是服务器收到请求后如果有数据, 立刻响应请求; 如果没有数据就会 hold 一段时间,这段时间内如果有数据立刻响应请求; 如果时间到了还没有数据, 则响应 http 请求;浏览器受到 http 响应后立在发送一个同样http 请求查询是否有数据;

http 长轮询的局限:

  1. 浏览器端对统一服务器同时 http 连接有最大限制, 最好同一用户只存在一个长轮询;
  2. 服务器端没有数据 hold 住连接时会造成浪费, 容易产生服务器瓶颈;

短轮询:http端轮询是服务器收到请求不管是否有数据都直接响应 http 请求; 浏览器受到 http 响应隔一段时间在发送同样的http 请求查询是否有数据;

http 短轮询的局限是实时性低;

两者相同点:

可以看出 http 长轮询和 http 短轮询的都会 hold 一段时间;

两者不同点

间隔发生在服务端还是浏览器端: http 长轮询在服务端会 hold 一段时间, http 短轮询在浏览器端 “hold”一段时间;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值