目录

                  JAVA基础

JVM 知识

开源框架知识

操作系统

多线程

TCP 与 HTTP

架构设计与分布式

算法

MySQL

中间件


 JAVA基础

1. JAVA 中的几种基本数据类型是什么,各自占用多少字节。

数据类型

关键字

内置类

内存占用字节数

布尔型

boolean

Boolean

1字节

字符型

char

Character

2字节

字节型

byte

Byte

1字节

短整型

short

Short

2字节

整形

int

Integer

4字节

长整型

long

Long

8字节

单精度型

float

Float

4字节

双精度型

double

Double

8字节

2. String类为什么是final的?

1.final方法比非final快一些
2.final关键字提高了性能。JVM和Java应用都会缓存final变量。
3.final变量可以安全的在多线程环境下进行共享,而不需要额外的同步开销。
4.使用final关键字,JVM会对方法、变量及类进行优化。
5.字符串是不可变的,所以在它创建的时候HashCode就被缓存了,不需要重新计算。这就使得字符串很适合作为Map中的键

Java String类为什么是final的? - 简书

【漫画】腾讯面试,我竟然输给了final关键字

3. String,Stringbuffer,StringBuilder的区别。

1.可变与不可变String类中使用字符数组保存字符串,如下就是,因为有“final”修饰符,所以可以知道string对象是不可变的。private final char value[];StringBuilder与StringBuffer都继承自AbstractStringBuilder类,在AbstractStringBuilder中也
是使用字符数组保存字符串,如下就是,可知这两种对象都是可变的。char[] value;2.是否多线程安全String中的对象是不可变的,也就可以理解为常量,显然线程安全。AbstractStringBuilder是StringBuilder与StringBuffer的公共父类,定义了一些字符串的基本操
作,如expandCapacity、append、insert、indexOf等公共方法。StringBuffer对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的 StringBuilder并没有对方法进行加同步锁,所以是非线程安全的。

4. ArrayList 和 LinkedList 有什么区别。

1. 是否保证线程安全: ArrayList 和 LinkedList 都是不同步的,也就是不保证线程安全;
2. 底层数据结构: Arraylist 底层使用的是Object数组;LinkedList 底层使用的是双向链表数据结构(注
意双向链表和双向循环链表的区别);
3. 插入和删除是否受元素位置的影响:① ArrayList 采用数组存储,② LinkedList 采用链表存储
4. 是否支持快速随机访问: LinkedList 不支持高效的随机元素访问,而 ArrayList 支持。快速随机访问
就是通过元素的序号快速获取元素对象(对应于get(int index)方法)。
5. 内存空间占用: ArrayList的空 间浪费主要体现在在list列表的结尾会预留一定的容量空间,而
LinkedList的空间花费则体现在它的每一个元素都需要消耗比ArrayList更多的空间(因为要存放直接后继和
直接前驱以及数据)。

补充内容:RandomAccess接口

public interface RandomAccess{

}

查看源码我们发现实际上 RandomAccess 接口中什么都没有定义。所以,在我看来 RandomAccess 接口不过
是一个标识罢了。标识什么? 标识实现这个接口的类具有随机访问功能。

在binarySearch()方法中,它要判断传入的list 是否RamdomAccess的实例,如果是,调用
indexedBinarySearch()方法,如果不是,那么调用iteratorBinarySearch()方法

ArraysList 实现了 RandomAccess 接口, 而 LinkedList 没有实现。为什么呢?我觉得还是和底层数据结
构有关!ArraysList 底层是数组,而 LinkedList 底层是链表。数组天然支持随机访问,时间复杂度为 
O(1),所以称为快速随机访问。链表需要遍历到特定位置才能访问特定位置的元素,时间复杂度为 O(n),
所以不支持快速随机访问。ArraysList 实现了 RandomAccess 接口,就表明了他具有快速随机访问功能。 
RandomAccess 接口只是标识,并不是说 ArraysList 实现 RandomAccess 接口才具有快速随机访问功能
的!

ArrayList:默认长度是10 每次扩容是原来的1.5倍。如果在添加的时候远数组是空的,就直接给一个10的长度,否则的话就加一,当需要的长度大于原来数组长度的时候就需要扩容了

下面再总结一下 list 的遍历方式选择:
实现了RadmoAcces接口的list,优先选择普通for循环 ,其次foreach,
未实现RadmoAcces接口的ist, 优先选择iterator遍历(foreach遍历底层也是通过iterator实现的),大
size的数据,千万不要使用普通for循环

5. 讲讲类的实例化顺序,比如父类静态数据,构造函数,字段,子类静态数据,构造函数,字段,当 new 的时候,他们的执行顺序。

父类静态数据 > 子类静态数据 > 父构造函数> 父字段 > 子构造函数 > 子字段

测试代码可以见:

https://gitee.com/lzhcode/maven-parent/blob/master/lzh-technology/src/main/java/com/lzhsite/technology/grammar/initStatic/

6. 用过哪些 Map 类,都有什么区别,HashMap 是线程安全的吗,并发下使用的 Map 是什么,他们内部原理分别是什么,比如存储方式,hashcode,扩容,默认容量等。

JDK1.8 之前 HashMap 底层是 数组和链表 结合在一起使用也就是 链表散列。HashMap 通过 key 的
hashCode 经过扰动函数处理过后得到 hash 值,然后通过 (n - 1) & hash 判断当前元素存放的位置(这里的 n 指的时数组的长度),如果当前位置存在元素的话,就判断该元素与要存入的元素的 hash 值以及 key 是否相同,如果相同的话,直接覆盖,不相同就通过拉链法解决冲突。所谓扰动函数指的就是 HashMap 的 hash 方法。使用 hash 方法也就是扰动函数是为了防止一些实现比较差的
hashCode() 方法 换句话说使用扰动函数之后可以减少碰撞。JDK1.8之后在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8)时,将链表转化为红黑树,以减少搜索时间。当 HashMap 中的元素个数超过数组大小 loadFactor时,就会进行数组扩容,loadFactor的默认值为 0.75,这
是一个折中的取值。也就是说,默认情况下,数组大小为 16,那么当 HashMap 中元素个数超过 16*0.75=12 的
时候,就把数组的大小扩展为 2*16=32,即扩大一倍,然后重新计算每个元素在数组中的位置,而这是一个非常
消耗性能的操作,所以如果我们已经预知 HashMap 中元素的个数,那么预设元素的个数能够有效的提高
HashMap 的性能。HashMap 包含如下几个构造器:HashMap():构建一个初始容量为 16,负载因子为 0.75 的 HashMap。
HashMap(int initialCapacity):构建一个初始容量为 initialCapacity,负载因子为 0.75 的 HashMap

7. JAVA8 的 ConcurrentHashMap为什么放弃了分段锁,有什么问题吗,如果你来设计,你如何设计。

从Java 8开始,HashMap,ConcurrentHashMap和LinkedHashMap在处理频繁冲突时将使用平衡树来代替链表,
当同一hash桶中的元素数量超过特定的值便会由链表切换到平衡树,这会将get()方法的性能从O(n)提高到O(logn)。ConcurrentHashMap适用于读者数量超过写者时,当写者数量大于等于读者时,CHM的性能是低于Hashtable和
synchronized Map的。这是因为当锁住了整个Map时,读操作要等待对同一部分执行写操作的线程结束。CHM适用
于做cache,在程序启动时初始化,之后可以被多个请求线程访问。正如Javadoc说明的那样,CHM是HashTable一
个很好的替代,但要记住,CHM的比HashTable的同步性稍弱

8. 有没有有顺序的Map 实现类,如果有,他们是怎么保证有序的。

在JAVA中,LRU的原生实现是JDK中LinkedHashMap。LinkedHashMap继承自HashMap
【实现原理】 简单说就是HashMap的每个节点做一个双向链表。
每次访问这个节点,就把该节点移动到双向链表的头部。满了以后,就从链表的尾部删除。
但是LinkedHashMap并是非线程安全(其实现中,双向链表的操作是没有任何线程安全的措施的)。
对于线程安全的HashMap,在JDK中有ConcurrentHashMap原生支持。

9. 抽象类和接口的区别,类可以继承多个类么,接口可以继承多个接口么,类可以实现多个接口么。

10.你能用Java覆盖静态方法吗?如果我在子类中创建相同的方法是否会编译时错误?

不能,但在子类中声明一个完全相同的方法不会编译错误,这称为隐藏在Java中的方法。

11. 讲讲你理解的 nio。他和 bio 的区别是啥,谈谈 reactor 模型。

Reactor模式首先是事件驱动的(基于NIO实现的),有一个或多个并发输入源,有一个Service Handler,有多个Request Handlers;这个Service Handler会同步的将输入的请求(Event)多路复用的分发给相应的Request Handle

Reactor模式详解 - 上善若水 - BlogJava

12. 反射的原理,反射创建类实例的三种方式是什么。

    //第一种表示方式--》实际在告诉我们任何一个类都有一个隐含的静态成员变量classClass class1 = Foo.class;//第二种表示方式  已经知道该类的对象通过getClass方法Class class2 = foo1.getClass();//第三种表达方式class3 = Class.forName("com.imooc.reflect.Foo");

13. 反射中,Class.forName 和 ClassLoader 区别。

解释
在java中Class.forName()和ClassLoader都可以对类进行加载。ClassLoader就是遵循双亲委派模型最终调用
启动类加载器的类加载器,实现的功能是“通过一个类的全限定名来获取描述此类的二进制字节流”,获取到二进制
流后放到JVM中。Class.forName()方法实际上也是调用的CLassLoader来实现的。最后调用的方法是forName0这个方法,在这个forName0方法中的第二个参数被默认设置为了true,这个参数代
表是否对加载的类进行初始化,设置为true时会类进行初始化,代表会执行类中的静态代码块,以及对静态变
量的赋值等操作。Class.forName(String className);这个方法的源码是@CallerSensitive
public static Class<?> forName(String className)throws ClassNotFoundException {Class<?> caller = Reflection.getCallerClass();return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}应用场景
在我们熟悉的Spring框架中的IOC的实现就是使用的ClassLoader。而在我们使用JDBC时通常是使用Class.forName()方法来加载数据库连接驱动。这是因为在JDBC规范中明确要
求Driver(数据库驱动)类必须向DriverManager注册自己。

14. 描述动态代理的几种实现方式,分别说出相应的优缺点。

Jdk cglib jdk底层是利用反射机制,需要基于接口方式,这是由于
Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this);
Cglib则是基于asm框架,实现了无反射机制进行代理,利用空间来换取了时间,代理效率高于jdk 

15. jdk代理与cglib 实现的区别。

JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,
cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,
并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。
采用非常底层的字节码生成技术

16. 为什么CGlib 方式可以对接口实现代理。

可以,效率低

17. final的用途。

final类不能被继承,没有子类,final类中的方法默认是final的。
final方法不能被子类的方法覆盖,但可以被继承。
final成员变量表示常量,只能被赋值一次,赋值后值不再改变。
final不能用于修饰构造方法

18. 写出三种单例模式实现。

饿汉单例

public class EagerSingleton {//饿汉单例模式//在类加载时就完成了初始化,所以类加载较慢,但获取对象的速度快private static EagerSingleton instance = new EagerSingleton();//静态私有成员,已初始化private EagerSingleton() {//私有构造函数}public static EagerSingleton getInstance()    //静态,不用同步(类加载时已初始化,不会有多线程的问题){return instance;}}

懒汉单例

public class LazySingleton {private LazySingleton() {System.out.println("LazySingleton is create");}private static LazySingleton instance = null;public static synchronized LazySingleton getInstance() {if (instance == null)instance = new LazySingleton();return instance;}
}

双检锁单例

/**
不可否认,synchronized关键字是可以保证单例,但是程序的性能却不容乐观,
原因在于getInstance()整个方法体都是同步的,这就限定了访问速度。
其实我们需要的仅仅是在首次初始化对象的时候需要同步,
对于之后的获取不需要同步锁。因此,可以做进一步的改进
**/public class DoubleCheckedLock {  private static volatile DoubleCheckedLock instance;    public static DoubleCheckedLock getInstance() {    if (instance == null) {  //step1  synchronized (DoubleCheckedLock.class) { //step2  if (instance == null) {  //step3 是不是多余?System.out.println("new DoubleCheckedLock");instance=new DoubleCheckedLock(); //step4  }}  }    return instance;    }    } 

静态内部类模式

/*** INSTANCE在创建过程中是线程安全的,所以说静态内部类形式的单例可保证线程安全,也能保证单例的唯一* 性,同时也延迟了单例的实例化。***/
public class SingleTon{private SingleTon(){}private static class SingleTonHoler{private static SingleTon INSTANCE = new SingleTon();}public static SingleTon getInstance(){return SingleTonHoler.INSTANCE;}
}

19. 如何在父类中为子类自动完成所有的 hashcode 和 equals 实现?这么做有何优劣。

20. 请结合 OO 设计理念,谈谈访问修饰符 public、private、protected、default 在应用设计中的作用。

21. 深拷贝和浅拷贝区别。

浅拷贝:①对于数据类型是基本数据类型的成员变量,浅拷贝会直接进行值传递,也就是将该属性值复制一份给新
的对象。因为是两份不同的数据,所以对其中一个对象的该成员变量值进行修改,不会影响另一个对象拷贝得到的
数据。②对于数据类型是引用数据类型的成员变量,比如说成员变量是某个数组、某个类的对象等,那么浅拷贝会
进行引用传递,也就是只是将该成员变量的引用值(内存地址)复制一份给新的对象。因为实际上两个对象的该成
员变量都指向同一个实例。在这种情况下,在一个对象中修改该成员变量会影响到另一个对象的该成员变量值。深拷贝:不仅要复制对象的所有基本数据类型的成员变量值,还要为所有引用数据类型的成员变量申请存储空间,
并复制每个引用数据类型成员变量所引用的对象,直到该对象可达的所有对象。也就是说,对象进行深拷贝要对整
个对象图进行拷贝!如果某个属性被transient修饰,那么该属性就无法被拷贝了

22. 数组和链表数据结构描述,各自的时间复杂度。

23. error 和 exception 的区别,CheckedException,RuntimeException 的区别。

1.Error(错误)是系统中的错误,程序员是不能改变的和处理的,是在程序编译时出现的错误,只能通过修改程序
才能修正。一般是指与虚拟机相关的问题,如系统崩溃,虚拟机错误,内存空间不足,方法调用栈溢等。对于这类
错误的导致的应用程序中断,仅靠程序本身无法恢复和和预防,遇到这样的错误,建议让程序终止。2.Exception(异常)表示程序可以处理的异常,可以捕获且可能恢复。遇到这类异常,应该尽可能处理异常,使程
序恢复运行,而不应该随意终止异常。Exception又分为两类CheckedException:(编译时异常) 需要用try——catch显示的捕获,对于可恢复的异常使用CheckedException。UnCheckedException(RuntimeException):(运行时异常)不需要捕获,对于程序错误(不可恢
复)的异常使用RuntimeException。

24. 请列出 5 个运行时异常。

NullPointerException - 空指针引用异常
ClassCastException - 类型强制转换异常。
IllegalArgumentException - 传递非法参数异常。
ArithmeticException - 算术运算异常
ArrayStoreException - 向数组中存放与声明类型不兼容对象异常
IndexOutOfBoundsException - 下标越界异常
NegativeArraySizeException - 创建一个大小为负数的数组错误异常
NumberFormatException - 数字格式异常
SecurityException - 安全异常
UnsupportedOperationException - 不支持的操作异常

25. 在自己的代码中,如果创建一个 java.lang.String 对象,这个对象是否可以被类加载器加载?为什么。

当Java程序请求加载器loader1加载Sample类时,loader1首先委托自己的父加载器去加载Sample类,若父加载
器能加载,则由父加载器完成加载任务,否则才由加载器loader1本身加载Sample类。加载过程中会先检查类是否被已加载,检查顺序是自底向上,从Custom ClassLoader到BootStrap
ClassLoader逐层检查,只要某个classloader已加载就视为已加载此类,保证此类只所有ClassLoader加载一
次。而加载的顺序是自顶向下,也就是说当发现这个类没有的时候会先去让自己的父类去加载,父类没有再让儿子
去加载那么在这个例子中我们自己写的String应该是被Bootstrap ClassLoader加载了,所以App
ClassLoader就不会再去加载我们写的String类了,导致我们写的String类是没有被加载的。

https://blog.csdn.net/u013206465/article/details/47170253

26. 说一说你对 java.lang.Object 对象中 hashCode 和 equals 方法的理解。在什么场景下需要重新实现这两个方法。

27. 在 jdk1.5 中,引入了泛型,泛型的存在是用来解决什么问题。

28. 这样的 a.hashcode() 有什么用,与 a.equals(b)有什么关系。

将对象放入到集合中时,首先判断要放入对象的hashcode值与集合中的任意一个元素的hashcode值是否相
等,如果不相等直接将该对象放入集合中。
如果hashcode值相等,然后再通过equals方法判断要放入对象与集合中的任意一个对象是否相等,如果equals判
断不相等,直接将该元素放入到集合中,否则不放入。equals与hashcode的关系
equals相等两个对象,则hashcode一定要相等。但是hashcode相等的两个对象不一定equals相等。 

详情原理请看

Java用自定义的类作为HashMap的key值情况的解析_击水三千里的专栏-CSDN博客

29. 有没有可能 2 个不相等的对象,有相同的 hashcode。

30. Java 中的 HashMap和 HashSet的区别,HashSet内部是如何工作的。

对于 HashSet 而言,它是基于 HashMap 实现的,HashSet 底层使用 HashMap 来保存所有元素,因此
HashSet 的实现比较简单,相关 HashSet 的操作,基本上都是直接调用底层 HashMap 的相关方法来完成,我
们应该为保存到 HashSet 中的对象覆盖 hashCode() 和 equals()

http://wiki.jikexueyuan.com/project/java-collection/hashset.html

31. 什么是序列化,怎么序列化,为什么序列化,反序列化会遇到什么问题,如何解决。

32.Java中按值传递与按引用传递的区别

值传递:(形式参数类型是基本数据类型):方法调用时,实际参数把它的值传递给对应的形式参数,形式参数只是
用实际参数的值初始化自己的存储单元内容,是两个不同的存储单元,所以方法执行中形式参数值的改变不影响实
际参数的值。引用传递:(形式参数类型是引用数据类型参数):也称为传地址。方法调用时,实际参数是对象(或数组),这时实
际参数与形式参数指向同一个地址,在方法执行中,对形式参数的操作实际上就是对实际参数的操作,这个结果在
方法结束后被保留了下来,所以方法执行中形式参数的改变将会影响实际参数。

34创建String的特性

字符串类(Java.lang.String)是Java中使用最多的类,也是最为特殊的一个类,很多时候,我们对它既熟悉
又陌生。在很多面试题中经常用String大做文章,只要掌握了String特性,对付它们就不再是困难了。
1、从根本上认识java.lang.String类和String池
首先,我建议先看看String类的源码实现,这是从本质上认识String类的根本出发点。
从源码中可以看到:
String类是final的,不可被继承。public final class String。
String类是的本质是字符数组char[], 并且其值不可改变。private final char value[];然后打开String类的API文档,从API中可以发现:
String类对象有个特殊的创建的方式,就是直接指定比如String x = "abc","abc"就表示一个字符串对象。
而x是"abc"对象的地址,也叫做"abc"对象的引用。
String对象可以通过“+”串联。串联后会生成新的字符串。也可以通过concat()来串联,这个后面会讲述。
Java运行时会维护一个String Pool(String池),JavaDoc翻译很模糊“字符串缓冲区”。String池用来存放
运行时中产生的各种字符串,并且池中的字符串的内容不重复。而一般对象不存在这个缓冲池,并且创建的对象
仅仅存在于方法的堆栈区。2、String对象的创建的特性
String对象的创建也很讲究,关键是要明白其原理。特性1:
当使用任何方式来创建一个字符串对象s时,Java运行时(运行中JVM)会拿着这个字符串的内容在String池中
找是否存在内容相同的字符串对象,如果不存在,则在池中创建一个字符串s,否则,不在池中添加。特性2:
Java中,只要使用new关键字来创建对象,则一定会(在堆区或栈区)创建一个新的对象。特性3:
使用直接指定、使用纯字符串串联或者在编译期间可以确定结果的变量表达式来创建String对象,则仅仅会检
查维护String池中的字符串,池中没有就在池中创建一个,有则罢了!但绝不会在堆栈区再去创建该String对
象;特性4:
使用包含编译期间无法确定结果的变量的表达式来创建String对象,则不仅会检查维护String池,而且还会在堆栈区创建一个String对象示例:
1、 直接指定,例如:下面代码运行结果为true;
String str1 = "abc";
String str2 = "abc";
System.out.println(str1 == str2);
2、 使用纯字符串串联,例如:下面代码运行结果为true;
String str1 = "abc";
String str2 = "ab" + "c";
System.out.println(str1 == str2);
3、 在编译期间可以确定结果的变量表达式,例如:下面代码运行结果为true。
final String str1 = "c"; //final类型的变量在编译时当常量处理
String str2 = "ab" + "c";
String str3 = "ab" + str1;
System.out.println(str2==str3);4、普通变量表达式进行创建字符串,例如:下面代码运行结果为false;
String str1 = "c";
String str2 = "ab" + "c";
String str3 = "ab" + str1;
System.out.println(str2==str3);

示例代码:

lzh-technology/src/main/java/com/lzhsite/technology/grammar/TestString.java · lzhcode/maven-parent - Gitee.com

33 String的Intern方法有哪些应用

Jdk6 以及以前的版本中,字符串的常量池是放在堆的Perm区的,Perm区是一个类静态的区域(方法区),主要存储
一些加载类的信息,常量池,方法片段等内容,默认大小只有4m
jdk7 主要对 intern 操作和常量池做了以下改动
1.将String常量池从Perm区移动到了Java Heap区
2.String#intern方法时,如果存在常量池的对象,会直接保存对象的引用,而不会重新创建对象。String对象的实例调用intern方法后,可以让JVM检查常量池,如果没有实例的value属性对应的字符串序列比
如"123"(注意是检查字符串序列而不是检查实例本身),就将本实例放入常量池,如果有当前实例的value属性对
应的字符串序列"123"在常量池中存在,则返回常量池中"123"对应的实例的引用而不是当前实例的引用,即使当
前实例的value也是"123"。可以使用string的intern方法来对同一个用户id(字符串)进行加锁,从而确同一个用户的操作的同步的

34、Java中的关键字 transient

Java中transient关键字的作用,简单地说,就是让某些被修饰的成员属性变量不被序列化

Java中的关键字 transient - 风一样的码农 - 博客园

35、Reader与InputStream两个类中的read()的区别

InputStream类的read()方法是从流里面取出一个字节,他的函数原型是 int read();
Reader类的read()方法则是从流里面取出一个字符(一个char),他的函数原型也是 int read(); 

36、Java Integer的缓存策略

package com.javapapers.java;public class JavaIntegerCache {public static void main(String... strings) {Integer integer1 = 3;Integer integer2 = 3;if (integer1 == integer2)System.out.println("integer1 == integer2");elseSystem.out.println("integer1 != integer2");Integer integer3 = 300;Integer integer4 = 300;if (integer3 == integer4)System.out.println("integer3 == integer4");elseSystem.out.println("integer3 != integer4");}
}

大多数人都认为上面的两个判断的结果都是 false。虽然它们的值相等,但由于比较的是对象,而对象的引用不一样,所以会认为两个 if 判断都是 false 的。在 Java 中,== 比较的是对象引用,而 equals 比较的是值。因此,在这个例子中,不同的对象有不同的引用,所以在进行比较的时候都应该返回 false。但是奇怪的是,这里两个相似的 if 条件判断却返回不同的布尔值。

下面是上面代码真正的输出结果,

integer1 == integer2
integer3 != integer4

Java 中 Integer 缓存实现

在 Java 5 中,为 Integer 的操作引入了一个新的特性,用来节省内存和提高性能。整型对象在内部实现中通过使用相同的对象引用实现了缓存和重用。

上面的规则适用于整数区间 -128 到 +127。

37.反射能获取到父类的私有方法吗?怎么防止反射破坏单例模式

反射能获取到父类的私有方法

单例模式一般构造方法都是private,目的就是为了防止外界调用私有构造器创建多个实例

但是反射能够访问私有的构造方法,只要反射获取的构造器调用setAccessible(true)方法即可。这样调用一次就会产生一个实例,调用多次就时多个实例,从而破坏单例。

只要在单例的私有构造器中添加判断单例是否已经构造的代码,如果单例之前已经构造,则抛出异常,如果没有构造,则无所谓。

还有一种就是枚举单例,枚举单例没有构造函数无法通过反射来攻击。

38.拦截器与过滤器的区别

  • 拦截器是基于java的反射机制的,而过滤器是基本函数回调。
  • 拦截器不依赖于servlet容器,过滤器依赖于servlet容器
  • 拦截器只能对action请求起作用,过滤器可以对几乎所有的请求起作用
  • 拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问
  • 在action的生命周期中,拦截器可以被多次调用,而过滤器只能在容器初始化时被调用过一次。

JVM 知识

1. 什么情况下会发生栈内存溢出。

至于是堆内存溢出还是方法区内存溢出还是栈内存溢出,其实可以用一些工具比如
JConsole来监视

2. JVM 的内存结构,Eden 和 Survivor 比例。

3. jvm 中一次完整的 GC 流程是怎样的,对象如何晋升到老年代,说说你知道的几种主要的 jvm 参数。

4. 你知道哪几种垃圾收集器,各自的优缺点,重点讲下 cms,包括原理,流程,优缺点

5. 垃圾回收算法的实现原理。

6. 当出现了内存溢出,你怎么排错。

内存溢出分析
JAVA dump查看线程运行情况:=====查看栈信息=======================
1.查询java程序pid netstat -ntpl | grep 80802.使用jstack [-l] 进程pid > xxx.log将进程里所有线程信息输入到指定文件中1)如果程序正常运行:使用jstack [-l] 进程pid > xxx.log将所有线程信息输入到指定文件中 2)如果程序无响应:使用 jstack -F [-m] [-l] 进程pid >xxx.log强制打印栈信息 =====查看堆信息=======================3.使用top命令找出占用cpu高(或者执行时间很长)的进程pid 4.使用top -H -p 线程pid 找出占用cpu高(或执行时间长)的线程pid 5.将占用cpu高的线程pid转换成16进制(window自带计算器) 6.dump该进程的内存jmap -dump:format=b,file=文件名 [进程pid]   将转换后的pid在开始输出的dump文件(xxx.log)中搜索对应线程信息 7.eclipse Memory Analyzer 对dump文件分析

7. JVM 内存模型的相关知识了解多少,比如重排序,内存屏障,happen-before,主内存,工作内存等。

volatile关键字禁止指令重排序(内存栅栏)有两层意思
1)当程序执行到volatile变量的读操作或者写操作时,在其前面的操作的更改肯定全部已经进行,且结果已经对
后面的操作可见;在其后面的操作肯定还没有进行;2)在进行指令优化时,不能将在对volatile变量访问的语句放在其后面执行,也不能把volatile变量后面的语
句放到其前面执行。Happen-Before 原则
1. 程序次序原则:一个线程内,按照程序代码顺序,书写在前面的操作先发生于书写在后面的操作。
2. volatile 规则:volatile 变量的写,先发生于读,这保证了 volatile 变量的可见性。
3. 锁规则:解锁(unlock) 必然发生在随后的加锁(lock)前。
4. 传递性:A先于B,B先于C,那么A必然先于C。
5. 线程的 start 方法先于他的每一个动作。
6. 线程的所有操作先于线程的终结。
7. 线程的中断(interrupt())先于被中断的代码。
8. 对象的构造函数,结束先于 finalize 方法。

并发编程之 Java 内存模型 + volatile 关键字 + Happen-Before 规则_击水三千里的专栏-CSDN博客

8. 简单说说你了解的类加载器。

JVM将类加载过程分为三个步骤:装载(Load),链接(Link)和初始化(Initialize)链接又分为三个步骤
验证:确保被加载类的正确性;
准备:为类的静态变量分配内存,并将其初始化为默认值;
解析:把类中的符号引用转换为直接引用;加载过程中会先检查类是否被已加载,检查顺序是自底向上,从Custom ClassLoader到BootStrap
ClassLoader逐层检查,只要某个classloader已加载就视为已加载此类,保证此类只所有ClassLoader加载一
次。而加载的顺序是自顶向下,也就是由上层来逐层尝试加载此类。1)Bootstrap ClassLoader
负责加载$JAVA_HOME中jre/lib/rt.jar里所有的class,由C++实现,不是ClassLoader子类2)Extension ClassLoader
负责加载java平台中扩展功能的一些jar包,包括$JAVA_HOME中jre/lib/*.jar或-Djava.ext.dirs指定目录下
的jar包3)App ClassLoader
负责记载classpath中指定的jar包及目录中class4)Custom ClassLoader
属于应用程序根据自身需要自定义的ClassLoader,如tomcat、jboss都会根据j2ee规范自行实现ClassLoader

9.spring里创建出来对象的存活时间

目前的系统,大部分是spring容器的对象,spring默认单实例方式加载,这些对象可能会存在老年代中。

但是方法内部new出来的对象不会存活太长时间,方法结束,引用消息,对象也会在下一次gc被回收。

10. 你们线上应用的 JVM 参数有哪些。

-Xms512m
-Xmx512m
-XX:MetaspaceSize=256m
-XX:MaxMetaspaceSize=256m
-Xmn256m
-XX:MaxDirectMemorySize=1g
-XX:SurvivorRatio=10
-XX:+UseConcMarkSweepGC
-XX:CMSMaxAbortablePrecleanTime=5000 ##垃圾回收会清理持久代,移除不再使用的classes,只有在 UseConcMarkSweepGC  也启用的情况下才有用
-XX:+CMSClassUnloadingEnabled ##使用cms作为垃圾回收使用80%后开始CMS收集
-XX:CMSInitiatingOccupancyFraction=80 ##使用手动定义初始化定义开始CMS收集
-XX:+UseCMSInitiatingOccupancyOnly ##使用并发的方式执行FGC
-XX:+ExplicitGCInvokesConcurrent ## 设置并行垃圾回收的线程数。此值可以设置与机器处理器数量相等
-XX:ParallelGCThreads=4 -Xloggc:$work_dir/logs/gc.log
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=$work_dir/logs/java.hprof

11. g1 和 cms 区别,吞吐量优先和响应优先的垃圾收集器选择。

Cms是以获取最短回收停顿时间为目标的收集器。基于标记-清除算法实现。比较占用cpu资源,切易造成碎片。G1是面向服务端的垃圾收集器,是jdk9默认的收集器,基于标记-整理算法实现。可利用多核、多cpu,保留分
代,实现可预测停顿,可控。 

12. 请解释如下 jvm 参数的含义:

-server
-Xms512m
-Xmx512m
-Xss1024K
-XX:PermSize=256m
-XX:MaxPermSize=512m
-XX:MaxTenuringThreshold=20
-XX:CMSInitiatingOccupancyFraction=80
-XX:+UseCMSInitiatingOccupancyOnly。##设置JVM最大可用内存为3550M。
-Xmx3550m#设置JVM初始内存为3550m,可以设置与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存。
-Xms3550m#设置每个线程的堆栈大小。在相同物理内 存下,减小这个值能生成更多的线程。但是操作系统对一
#个进程内的线程数还是有限制的,不能无限生成,
#经验值在3000~5000左右
-Xss128k #设置持久代大小为16m
-XX:MaxPermSize=16m#设置垃圾最大年龄。如果设置为0的话,则年轻代对象不经过Survivor区,直
#接进入年老代。对于年老代比较多的应用,可以提高效率。
#如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象再年轻代的存活
#时间,增加在年轻代即被回收的概论。
-XX:MaxTenuringThreshold=0

系统学习JVM知识这篇文章讲的比较清楚

JVM原理讲解和调优_击水三千里的专栏-CSDN博客

问题和实战

https://mp.weixin.qq.com/s/5lJdrsj_CGnG_w3CjJ8iPg

https://mp.weixin.qq.com/s/sI2qQ8e7TOa4qGqi6-kQgA

开源框架知识

1. 简单讲讲 tomcat 结构,以及其类加载器流程。

tomcat结构

Tomcat的核心组件就Connector和Container,一个Connector+一个Container(Engine)构成一个Service,Service就是对外提供服务的组件,有了Service组件Tomcat就能对外提供服务了,但是光有服务还不行,还需要有环境让你提供服务才行,所以最外层的Server就是为Service提供了生存的土壤。

Container 是容器的父接口,所有子容器都必须实现这个接口,Container 容器的设计用的是典型的责任链的设计模式,它有四个子容器组件构成,分别是:Engine、Host、Context、Wrapper,这四个组件不是平 行的,而是父子关系,Engine 包含 Host,Host 包含 Context,Context 包含 Wrapper。通常一个 Servlet class 对应一个 Wrapper,如果有多个 Servlet 就可以定义多个 Wrapper,如果有多个 Wrapper 就要定义一个更高的 Container 了

在Tomcat 6中默认情况下,Jar包的加载顺序是:

1)JRE中的Java基础包
2)Web应用WEB-INF\lib下的包
3)Tomcat\lib下的包

线程模型:支持以下四种线程模型。

3. 讲讲 Spring 加载流程。

4. 讲讲 Spring 事务的传播属性。

PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。

5. Spring 如何管理事务的。

6. Spring 怎么配置事务(具体说出一些关键的 xml元素)。

tx:advice,aop:config

7. 说说你对 Spring 的理解,非单例注入的原理?它的生命周期?循环注入的原理,aop 的实现原理,说说 aop 中的几个术语,它们是怎么相互工作的。

8. SpringMVC 中 DispatcherServlet初始化过程。

1. 用户向服务器发送请求,请求被Spring 前端控制Servelt DispatcherServlet捕获;
2. DispatcherServlet对请求URL进行解析,得到请求资源标识符(URI)。然后根据该URI,调用HandlerMapping获得该Handler配置的所有相关的对象(包括Handler对象以及Handler对象对应的拦截器),最后以HandlerExecutionChain对象的形式返回;
3. DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter。(附注:如果成功获得HandlerAdapter后,此时将开始执行拦截器的preHandler(...)方法)
4.  提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)。 在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作:HttpMessageConveter: 将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息数据转换:对请求消息进行数据转换。如String转换成Integer、Double等数据根式化:对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等数据验证: 验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中
5.  Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象;
6.  根据返回的ModelAndView,选择一个适合的ViewResolver(必须是已经注册到Spring容器中的ViewResolver)返回给DispatcherServlet ;
7. ViewResolver 结合Model和View,来渲染视图

9.SpringBoot主要解决了什么问题

1. 创建独立的 Spring 应用程序
2. 嵌入的 Tomcat,无需部署 WAR 文件
3. 简化 Maven 配置
4. 自动配置 Spring
5. 供生产就绪型功能,如指标,健康检查和外部配置
6. 自定义代码配置代替XML

操作系统

1. Linux 系统下你关注过哪些内核参数,说说你知道的。

2. Linux 下 IO 模型有几种,各自的含义是什么。

1.BIO(blocking IO):同步阻塞 I/O
2.NIO(nonblocking IO):同步非阻塞 I/O
3.多路复用IO( IO multiplexing)
4.信号驱动I/O( signal driven IO)
5.异步 I/O(asynchronous IO)

【Linux基础】Linux的5种IO模型详解_白夜行-CSDN博客_基本io模型

3. epoll 和 poll 有什么区别。

select、poll、epoll都是IO多路复用的机制,先是监听多个文件描述符FD,一旦某个FD就绪,就可以进行相应
的读写操作。但是select、poll、epoll本质都是同步I/O,他们都需要在读写事件就绪之后自己负责读写,即这个读写过程是阻塞的

总结:
(1)select,poll实现需要自己不断轮询所有fd集合,直到设备就绪,期间可能要睡眠和唤醒多次交替。而epoll其实也需要调用 epoll_wait不断轮询就绪链表,期间也可能多次睡眠和唤醒交替,但是它是设备就绪时,调用回调函数,把就绪fd放入就绪链表中,并唤醒在epoll_wait中进入睡眠的进程。虽然都要睡眠和交替,但是select和poll在“醒着”的时候要遍历整个fd集合,而epoll在“醒着”的 时候只要判断一下就绪链表是否为空就行了,这节省了大量的CPU时间。这就是回调机制带来的性能提升。

(2)select,poll每次调用都要把fd集合从用户态往内核态拷贝一次,并且要把current往设备等待队列中挂一次,而epoll只要 一次拷贝,而且把current往等待队列上挂也只挂一次(在epoll_wait的开始,注意这里的等待队列并不是设备等待队列,只是一个epoll内部定义的等待队列)。这也能节省不少的开销。

4. 平时用到哪些 Linux 命令。

递归计算当前目录的文件,包括隐藏文件。

# find . -type f | wc -l

语法:

find : 搜索目录结构中的文件

-type : 文件类型

f : 常规文件

-l : 输出换行符的数量

wc [选项] 文件 :该命令统计给定文件中的字节数、字数、行数。如果没有给出文件名,则从标准输入读取。wc同时也给出所有指定文件的总统计数。字是由空格字符区分开的最大字符串。

该命令各选项含义如下
- c 统计字节数。
- l 统计行数。
- w 统计字数。

$ wc - lcw file1 file2
4 33 file1
7 52 file2
11 11 85 total

批量替换文本内容

sed -i 's/^Str/String/'  replace.txt      把每行第一个Str替换为String

sed -i 's/^Str/String/g'  replace.txt    把Str全文替换为String

sed -i 's/\.$/\;/'  replace.txt                把.结尾替换为;

sed -i 's/^ *$/d'  replace.txt               删除文本中的空行

sed -i 's/Integer/d'  replace.txt          删除Integer所在行

检索文件内容常用指令

对文件进行统计

 awk {print $1 $4} netstat.txt

awk '$1="tcp"&&$2=1 {print $0}' netstat.txt

awk '($1="tcp"&&$2=1 )|| NR=1 {print $0}' netstat.txt   在第二步的基础上打印表头

awk -F "," test.txt                                                          以,为分割符去分割文件内容

grep'partial\[true\] bsc-plat-al-data.info.log | 'awk 'enginearr[$1++]END for(in inenginearr)print i"\t"enginearr[i]}'

5. 用一行命令查看文件的最后五行。

输出test文件的后五行:liyi@liyi:~/Desktop > tail -n 5 test输出test文件的前五行:liyi@liyi:~/Desktop > head -n 5 test

6. 用一行命令输出正在运行的 java 进程。

jps

7. 介绍下你理解的操作系统中线程切换过程。

线程的切换只有指令的切换,同处于一个进程里面,不存在映射表的切换。进程的切换就是在线程切换的基础上加上映射表的切换。

8. 进程和线程的区别。

9.用户态和内核态是什么?

内核态: CPU可以访问内存所有数据, 包括外围设备, 例如硬盘, 网卡. CPU也可以将自己从一个程序切换到另一个程序

用户态: 只能受限的访问内存, 且不允许访问外围设备. 占用CPU的能力被剥夺, CPU资源可以被其他程序获取

10.怎么批量替换一个文件夹下所有文件中的一个字符?

sed -i "s/oldString/newString/g" `grep oldString -rl /path`

多线程

1. 多线程的几种实现方式,什么是线程安全。

2. volatile 的原理,作用,能代替锁么。

3. 画一个线程的生命周期状态图。

4. sleep 和 wait 的区别。

5. Lock 与 Synchronized 的区别。

  总结来说,Lock和synchronized有以下几点不同:1)Lock是一个接口,而synchronized是Java中的关键字,synchronized是内置的语言实现;2)synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而Lock在发生异
常时,如果没有主动通过unLock()去释放锁,则很可能造成死锁现象,因此使用Lock时需要在finally块中释放
锁;3)Lock可以让等待锁的线程响应中断,而synchronized却不行,使用synchronized时,等待的线程会一直
等待下去,不能够响应中断;4)通过Lock可以知道有没有成功获取锁,而synchronized却无法办到。5)Lock可以提高多个线程进行读操作的效率。在性能上来说,如果竞争资源不激烈,两者的性能是差不多的,而当竞争资源非常激烈时(即有大量线程同时
竞争),此时Lock的性能要远远优于synchronized。所以说,在具体使用时要根据适当情况选择。

6. synchronized 的原理是什么,解释以下名词:重排序,自旋锁,偏向锁,轻量级锁,可重入锁,公平锁,非公平锁,乐观锁,悲观锁。

 synchronized 的原理

monitor对象存在于每个Java对象的对象头中(存储的指针的指向),synchronized锁便是通过这种方式获取锁的

偏向锁

大多数情况下,锁不仅不存在多线程竞争,而且总是由同一线程多次获得,为了让线程获得锁的代价更低而引人了偏向锁

轻量级锁

如果没有竞争,轻量级锁使用CAS操作,避免使用互斥量

如果存在竞争,除了互斥量的开销,还有 CAS的操作,不仅没有提升,反而性能会下降

重量级锁

重量级锁,使用的是系统互斥量实现的

Synchronized 用法和底层原理_击水三千里的专栏-CSDN博客

轻量级锁、重量级锁都是啥玩意_叫我刘三青-CSDN博客_轻量级锁

7. 用过哪些原子类,他们的原理是什么。

8. 用过线程池吗,newCache 和 newFixed 有什么区别,他们的原理简单概括下,构造函数的各个参数的含义是什么,比如 coreSize,maxsize 等。

Executors.newCachedThreadPool():无限线程池。Executors.newFixedThreadPool(nThreads):创建固定大小的线程池。Executors.newSingleThreadExecutor():创建单个线程的线程池。1.ExecutorService threadPool = Executors.newCachedThreadPool();
SynchronousQueue是一个没有数据缓冲的BlockingQueue,生产者线程对其的插入操作put必须等待消费者的移
除操作take。所以newCachedThreadPool实际项目一般也很少运用2.ExecutorService executor = Executors.newFixedThreadPool(3);
这个线程池的队列LinkedBlockingQueue没有指定默认大小,高并发环境下
在对内存压力很大,所以生产环境一般都不使用这个

9. 线程池的关闭方式有几种,各自的区别是什么。

shutdown() 执行后停止接受新任务,会把队列的任务执行完毕。shutdownNow() 也是停止接受新任务,但会中断所有的任务,将线程池状态变为 stop。

详细介绍见:讲解线程池的一篇干货,很干很干!

10. 假如有一个第三方接口,有很多个线程去调用获取数据,现在规定每秒钟最多有 10 个线程同时调用它,如何做到。

基于redis分布式限流超时时间设为1s

详细介绍见:单机限流和分布式应用限流_击水三千里的专栏-CSDN博客_分布式限流和单机限流

11. spring 的 controller 是单例还是多例,怎么保证并发的安全。

singleton : bean在每个Spring ioc 容器中只有一个实例。
prototype:一个bean的定义可以有多个实例。
request:每次http请求都会创建一个bean,该作用域仅在基于web的Spring ApplicationContext情形下有效。

12. 用三个线程按顺序循环打印 abc 三个字母,比如 abcabcabc。

public class PrintABC {  public static Boolean isThreadA = true;  public static Boolean isThreadB = false;  public static Boolean isThreadC = false;  public static void main(String[] args) {  final PrintABC abc = new PrintABC();  new Thread(new Runnable() {  public void run() {  for (int i = 0; i < 10; i++) {  synchronized (abc) {  while(!isThreadA) {  try {  abc.wait();  } catch (InterruptedException e) {  // TODO Auto-generated catch block  e.printStackTrace();  }  }  System.out.print("A");  isThreadA = false;  isThreadB = true;  isThreadC = false;  abc.notifyAll();  }  }  }  }).start();  new Thread(new Runnable() {  public void run() {  for (int i = 0; i < 10; i++) {  synchronized (abc) {  while(!isThreadB) {  try {  abc.wait();  } catch (InterruptedException e) {  // TODO Auto-generated catch block  e.printStackTrace();  }  }  System.out.print("B");  isThreadA = false;  isThreadB = false;  isThreadC = true;  abc.notifyAll();  }  }  }  }).start();  new Thread(new Runnable() {  public void run() {  for (int i = 0; i < 10; i++) {  synchronized (abc) {  while(!isThreadC) {  try {  abc.wait();  } catch (InterruptedException e) {  // TODO Auto-generated catch block  e.printStackTrace();  }  }  System.out.print("C");  isThreadA = true;  isThreadB = false;  isThreadC = false;  abc.notifyAll();  }  }  }  }).start();  }
}

13. ThreadLocal 用过么,用途是什么,原理是什么,用的时候要注意什么。

14. 如果让你实现一个并发安全的链表,你会怎么做。

聊聊高并发(三十二)实现一个基于链表的无锁Set集合_ITer_ZC的专栏-CSDN博客

15. 有哪些无锁数据结构,他们实现的原理是什么。

ConcurrentLikedQueue是一个适用于高并发场景下的队列,通过无锁(CAS)的方式,实现了高并发状态下的高性能, 通常ConcurrentLikedQueue性能好于BlockingQueue。
  
  ConcurrentLinkedQueue的其他方法:

peek():获取表头元素但不移除队列的头,如果队列为空则返回null。
   remove(Object obj):移除队列已存在的元素,返回true,如果元素不存在,返回false。         add(E e):将指定元素插入队列末尾,成功返回true,失败返回false(此方法非线程安全的方法,不推荐使用)。

注意:
  虽然ConcurrentLinkedQueue的性能很好,但是在调用size()方法的时候,会遍历一遍集合,对性能损害较大,执行很慢,最好用isEmpty()方法。
  ConcurrentLinkedQueue不允许插入null元素,会抛出空指针异常。
  ConcurrentLinkedQueue是无界的,所以使用时,一定要注意内存溢出的问题。即对并发不是很大中等的情况下使用,不然占用内存过多或者溢出,对程序的性能影响很大

16. 讲讲 java 同步机制的 wait 和 notify。

17. 多线程如果线程挂住了怎么办。

18. countdowlatch 和 cyclicbarrier的内部原理和用法,以及相互之间的差别。

1.CountDownLatch减计数,CyclicBarrier加计数。
2.CountDownLatch是一次性的,CyclicBarrier可以重用。应用场景
对于CountDownLatch来说,重点是那个“一个线程”, 是它在等待, 而另外那N的线程在把“某个事情”做完之后可以继续等待,可以终止。
对于CyclicBarrier来说,重点是那N个线程,他们之间任何一个没有完成,所有的线程都必须等待。

19. 使用 synchronized 修饰静态方法和非静态方法有什么区别。

 所有的非静态同步方法用的都是同一把锁——实例对象本身,也就是说如果一个实例对象的非静态同步方法获取锁后,该实例对象的其他非静态同步方法必须等待获取锁的方法释放锁后才能获取锁,可是别的实例对象的非静态同步方法因为跟该实例对象的非静态同步方法用的是不同的锁,所以毋须等待该实例对象已获取锁的非静态同步方法释放锁就可以获取他们自己的锁。而所有的静态同步方法用的也是同一把锁——类对象本身,这两把锁是两个不同的对象,所以静态同步方法与非静态同步方法之间是不会有竞态条件的。但是一旦一个静态同步方法获取锁后,其他的静态同步方法都必须等待该方法释放锁后才能获取锁,而不管是同一个实例对象的静态同步方法之间,还是不同的实例对象的静态同步方法之间,只要它们同一个类的实例对象!

20. 简述 ConcurrentLinkedQueue 和 LinkedBlockingQueue 的用处和不同之处。

LinkedBlockingQueue 一个由链接节点支持的可选有界阻塞队列。

ConcurrentLinkedQueue 通过compare and swap(简称CAS)协议的方式,来保证多线程情况下数据的安全,不加锁,主要使用了Java中的要使用了Java中的sun.misc.Unsafe类来实现

21. 导致线程死锁的原因?怎么解除线程死锁。

一、导致线程死锁的原因两个不同的线程加锁的顺序不一样二、怎么解除线程死锁1.加锁过期时限,当一个线程持有锁的时间达到一定值时,wait释放锁,等待一段随机的时间再重试2.当几个线程都要访问共享资源A、B、C时,保证使每个线程都按照同样的顺序去访问它们,比如都先访问A,在访问B和C。 

22. 非常多个线程(可能是不同机器),相互之间需要等待协调,才能完成某种工作,问怎么设计这种协调方案。

CountDownLatch,CyclicBarrier

23. 正确使用 Volatile 变量

正确使用 volatile 变量的条件
 
您只能在有限的一些情形下使用 volatile 变量替代锁。要使 volatile 变量提供理想的线程安全,必须同时满足下面两个条件:
 
1对变量的写操作不依赖于当前值。
2该变量没有包含在具有其他变量的不变式中。

并发编程之 Java 内存模型 + volatile 关键字 + Happen-Before 规则_击水三千里的专栏-CSDN博客

并发编程之volatile 关键字白话文解读_击水三千里的专栏-CSDN博客

24. BIO,NIO与AIO的区别

Java BIO :在JDK1.4出来之前,我们建立网络连接的时候采用BIO模式,需要先在服务端启动一个
ServerSocket,然后在客户端启动Socket来对服务端进行通信,默认情况下服务端需要对每个请求建立一堆线
程等待请求,而客户端发送请求后,先咨询服务端是否有线程相应,如果没有则会一直等待或者遭到拒绝请求,
如果有的话,客户端会线程会等待请求结束后才继续执行。Java NIO : 同步非阻塞,服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用
器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。Java AIO(NIO.2) : 异步非阻塞,NIO不同,当进行读写操作时,只须直接调用API的read或write方法即可,
这两种方法均为异步的。NIO方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,并发局限于应用中,编程比较复
杂,JDK1.4开始支持。AIO方式使用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用OS参与并发操作,编程比
较复杂,JDK7开始支持

BIO,NIO与AIO的区别 - BarryW - 博客园

25.synchronized和reentrantlock异同

相同点

都实现了多线程同步和内存可见性语义

都是可重入锁

不同点

实现机制不同 synchronized通过java对象头锁标记和Monitor对象实现 reentrantlock通过CAS、
ASQ(AbstractQueuedSynchronizer)和locksupport(用于阻塞和解除阻塞)实现 synchronized依赖jvm内
存模型保证包含共享变量的多线程内存可见性 reentrantlock通过ASQ的volatile state保证包含共享变量的多
线程内存可见性

使用方式不同 synchronized可以修饰实例方法(锁住实例对象)、静态方法(锁住类对象)、代码块(显示指定
锁对象) reentrantlock显示调用trylock()/lock()方法,需要在finally块中释放锁

功能丰富程度不同 reentrantlock提供有限时间等候锁(设置过期时间)、可中断锁(lockInterruptibly)、
condition(提供await、signal等方法)等丰富语义 reentrantlock提供公平锁和非公平锁实现 
synchronized是非公平锁,不可设置等待时间、不可被中断(interrupted),

26.公平锁和非公平锁

公平锁:

获取不到锁的时候,会自动加入队列,等待线程释放后,队列的第一个线程获取锁

非公平锁:

获取不到锁的时候,会自动加入队列,等待线程释放锁后所有等待的线程同时去竞争

27.为什么Java中 wait 方法需要在 synchronized 的方法中调用?

1) Java 会抛出 IllegalMonitorStateException,如果我们不调用来自同步上下文的wait(),notify()或者notifyAll()方法。

2) 如果我们不在同步方法或块中调用它们就可能存在wait()和 notify()之间的竞态条件。由于竞态条件,没有获取到锁,我们可能会丢失通知,如果我们使用缓冲区或只使用一个元素,生产线程将永远等待,你的程序将挂起

26.线程池的submit和execute方法区别

1、submit有返回值,而execute没有

submit它的功能是提交指定的任务去执行并且返回Future对象,即执行的结果

2、submit方便Exception处理
意思就是如果你在你的task里会抛出checked或者unchecked exception,而你又希望外面的调用者能够感知这些exception并做出及时的处理,那么就需要用到submit,通过捕获Future.get抛出的异常。

TCP 与 HTTP

1. http/1.0、http/1.1和http2.0有什么区别

在http1.0中,当建立连接后,客户端发送一个请求,服务器端返回一个信息后就关闭连接,
当浏览器下次请求的时候又要建立连接,显然这种不断建立连接的方式,会造成很多问题。在http1.1中,引入了持续连接的概念,通过这种连接,浏览器可以建立一个连接之后,
发送请求并得到返回信息,然后继续发送请求再次等到返回信息,也就是说客户端可以连续发送多个请求,而不用等待每一个响应的到来。在http/2.0中,支持多路复用技术,同一个连接并发处理多个请求(NIO),http/1.1可以通过建立多个TCP解决

2. TCP 三次握手和四次挥手的流程,为什么断开连接要4次,如果握手只有两次,会出现什么。

知识铺垫

TCP看似复杂,其实可以归纳为以下5种报文
(1)SYN
(2)Data (唯一携带用户数据)
(3)FIN
(4)Reset
(5)ACK

  • 其中1、2、3分别为建立连接、数据传输、断开连接,这三种报文对方接收到一定要ACK确认,为何要确认,因为这就是可靠传输的依赖的机制。如果对方在超时时间内不确认,发送方会一直重传,直到对方确认为止、或到达重传上限次数而Reset连接。
  • 4、5 为重置连接报文、确认ACK报文,这两种报文对方接收到要ACK确认吧?不需要!自然发送方也不会重传这2种类型的报文。

为何Reset报文不需要ACK确认?

因为发送Reset报文的一端,在发送完这个报文之后,和该TCP Session有关的内存结构体瞬间全部释放,无论对方收到或没有收到,关系并不大。

  • 如果对方收到Reset报文,也会释放该TCP Session 的相关内存结构体。
  • 如果对方没有收到Reset 报文,可能会继续发送让接收方弹射出Reset报文的报文,到最后对方一样会收到Reset 报文,并最终释放内存。

为何ACK报文不需要ACK确认?

这里的ACK报文,是指没有携带任何数据的裸ACK报文,对方收到这样的ACK报文,自然也不需要ACK。
否则,对方为了ACK己方的ACK,那己方收到对方的ACK,也要ACK对方的ACK,这就是一个死循环,永无止息。所以为了避免这个死循环,一律不允许ACK对方的裸ACK报文。

TCP连接建立过程:
1、客户端向服务器发送SYN,其中seq=x。
2、服务器收到SYN报文段后,发送SYN+ACK,其中seq=y,确认号=x+1。
3、客户端收到SYN+ACK报文段后,发送ACK,确认号=y+1。服务器收到ACK报文段后,连接建立。

TCP连接断开过程:
1、客户端TCP模块在收到应用程序的通知后,发送FIN,seq=x。
2、服务器收到FIN报文段,发送ACK,确认号=x+1,并且通知应用程序客户端关闭了连接。客户端收到ACK报文段。
3、服务器端的应用程序通知TCP关闭连接,服务器端TCP发送FIN+ACK,seq=y,确认号=x+1(此时服务端已经断开连接)。
4、客户端收到FIN+ACK报文段后,发送ACK,确认号y+1。服务器收到ACK报文段后,连接断开。

为什么TCP建立连接不是四次握手?

  1. A 发送SYN 报文给B,这是第一次报文交互。
  2. B发送ACK确认A的SYN报文,这是第二次报文交互
  3. B发送自己的SYN报文给A,这是第三次报文交互
  4. A需要ACK确认B的SYN报文,这是第四次报文交互

以上的演绎没有问题,但是报文2、3为何要分开发送呢?增加了延迟不说,同时还白白浪费了网络的带宽

 为什么断开连接要4次,如果握手只有两次,会出现什么?

为什么不把断开连接的第二步,第三步合在一起进行呢?
因为,第二步中,服务器端通知应用程序并获得反馈信息可能需要可观的时间,这可能涉及人机交互操作,也可能服务器应用层暂时还不想关闭连接。第二步结束后,服务器还可以继续通过这条连接发送数据给客户端,客户端已经不能发送数据了,但是仍然可以回复ACK。第二步中服务器立即发送确认是为了防止客户端重传FIN报文。

TCP连接建立只需要三次握手,为什么断开连接需要四次挥手?_刘一凡的博客-CSDN博客_tcp断开为什么需要四次

帐号已迁移

3. TIME_WAIT 和 CLOSE_WAIT 的区别。

CLOSE_WAIT:等待关闭,是被动关闭连接形成的,也就是第二次挥手时产生的状态。也就是当对方close一个SOCKET后发送FIN报文给自己,系统会回应一个ACK报文给对方,此时进入CLOSE_WAIT状态。接着,我们需要考虑的事情是查看是否还有数据发送给对方,如果没有就可以close这个链接,发送FIN给对方,也既关闭连接。所以在CLOSE_WAIT状态时,需要查看自己是否需要关闭连接。

TIME_WAIT:是主动关闭连接方形成的,表示收到了对方的FIN报文,并发送ACK报文,等待2MSL(Maximum Segment Lifetime:报文最大生存时间)约4分钟时间后进入CLOSE状态。主要是防止最后一个ACK丢失(之最后一个客户端ack),由于TIME_WAIT等待时间较长,因此server端尽量减少关闭。

4. 说说你知道的几种 HTTP 响应码,比如 200, 302, 404。

200 OK:表示客户端请求成功。
301 redirect: 301 代表永久性转移(Permanently Moved)
302 redirect: 302 代表暂时性转移(Temporarily Moved )
400 Bad Request 语义有误,不能被当前服务器理解。
401 Unauthorized 当前请求需要用户验证。
403 Forbidden 服务器收到消息,但是拒绝提供服务。
404 Not Found 请求资源不存在。
408 Request Timeout 请求超时,客户端没有在服务器预备等待的时间内完成发送。
500 Internal Server Error 服务器发生不可预期的错误。
503 Server Unavailable 由于临时的服务器维护或过载,服务器当前不能处理请求,此状况知识临时的,可恢
复

5. 当你用浏览器打开一个链接的时候,计算机做了哪些工作步骤。

域名解析--> 发起TCP的3次握手 --> 建立TCP连接后发起http请求 --> 服务器响应http请求--> 浏览器得到html代码 --> 浏览器解析html代码,并请求html代码中的资源(如js、css、图片等) --> 浏览器对页面进行渲染呈现给用户

6. TCP/IP 如何保证可靠性,说说 TCP 头的结构。

7. 如何避免浏览器缓存。

无法被浏览器缓存的请求:
HTTP信息头中包含Cache-Control:no-cache,pragma:no-cache,或Cache-Control:max-age=0等告诉浏览器不用缓存的请求
需要根据Cookie,认证信息等决定输入内容的动态请求是不能被缓存的
经过HTTPS安全加密的请求(有人也经过测试发现,ie其实在头部加入Cache-Control:max-age信息,firefox在头部加入Cache-Control:Public之后,能够对HTTPS的资源进行缓存,参考《HTTPS的七个误解》)
POST请求无法被缓存
HTTP响应头中不包含Last-Modified/Etag,也不包含Cache-Control/Expires的请求无法被缓存

8. 简述 Http 请求 get 和 post 的区别以及数据包格式。

GET提交,请求的数据会附在URL之后(就是把数据放置在HTTP协议头<request-line>中
POST提交:把提交的数据放置在是HTTP包的包体<request-body>中

9. 简述 HTTP 请求的报文格式。

一个HTTP请求报文由请求行(request line)、请求头部(header)、空行和请求数据4个部分组成

HTTP请求报文和HTTP响应报文_zhangliang_571的专栏-CSDN博客_http请求报文和响应报文

10. HTTPS 的加密方式是什么,讲讲整个加密解密流程。

  HTTPS其实是有两部分组成:HTTP + SSL / TLS,也就是在HTTP上又加了一层处理加密信息的模块。服务端和客户端的信息传输都会通过TLS进行加密,所以传输的数据都是加密后的数据

1. 客户端发起HTTPS请求

2. 服务端的配置

采用HTTPS协议的服务器必须要有一套数字证书,可以自己制作,也可以向组织申请

3. 传送证书

这个证书其实就是公钥,只是包含了很多信息,如证书的颁发机构,过期时间等等。

4. 客户端解析证书

  这部分工作是有客户端的TLS来完成的,首先会验证公钥是否有效,比如颁发机构,过期时间等等,如果发现异常,则会弹出一个警告框,提示证书存在问题。如果证书没有问题,那么就生成一个随机值(私匙)。然后用证书对该随机值进行加密。就好像上面说的,把随机值用锁头锁起来,这样除非有钥匙,不然看不到被锁住的内容。

5. 传送加密信息

  这部分传送的是用证书加密后的随机值,目的就是让服务端得到这个随机值,以后客户端和服务端的通信就可以通过这个随机值来进行加密解密了。

6. 服务段解密信息

  服务端用私钥解密后,得到了客户端传过来的随机值(私钥),然后把内容通过该值进行对称加密。所谓对称加密就是,将信息和私钥通过某种算法混合在一起,这样除非知道私钥,不然无法获取内容,而正好客户端和服务端都知道这个私钥,所以只要加密算法够彪悍,私钥够复杂,数据就够安全。

7. 传输加密后的信息

  这部分信息是服务端用私钥加密后的信息,可以在客户端被还原。

8. 客户端解密信息

  客户端用之前生成的私钥解密服务端传过来的信息,于是获取了解密后的内容。整个过程第三方即使监听到了数据,也

11.对称加密和非对称加密

12.TCP与UDP的区别是什么

1.基于连接与无连接;
2.对系统资源的要求(TCP较多,UDP少);
3.UDP程序结构较简单;
4.流模式与数据报模式 ;
5.TCP保证数据正确性,UDP可能丢包,TCP保证数据顺序,UDP不保证。

UDP应用场景:
1.面向数据报方式
2.网络数据大多为短消息 
3.拥有大量Client
4.对数据安全性无特殊要求
5.网络负担非常重,但对响应速度要求高

架构设计与分布式

1. 常见的缓存策略有哪些,你们项目中用到了什么缓存系统,如何设计的。

2. 用 java 自己实现一个 LRU。

3. 分布式集群下如何做到唯一序列号。

4. 设计一个秒杀系统,30 分钟没付款就自动关闭交易。

如何设计一个秒杀系统_击水三千里的专栏-CSDN博客

5. 如何使用 redis 和 zookeeper 实现分布式锁?有什么区别优缺点,分别适用什么场景。

Redis 的分布式锁而言,它有以下缺点:

它获取锁的方式简单粗暴,获取不到锁直接不断尝试获取锁,比较消耗性能。

另外来说的话,Redis 的设计定位决定了它的数据并不是强一致性的,在某些极端情况下,可能会出现问题。锁的模型不够健壮

对于 ZK 分布式锁而言:

ZK 天生设计定位就是分布式协调,强一致性。锁的模型健壮、简单易用、适合做分布式锁。

如果获取不到锁,只需要添加一个监听器就可以了,不用一直轮询,性能消耗较小。

但是 ZK 也有其缺点:如果有较多的客户端频繁的申请加锁、释放锁,对于 ZK 集群的压力会比较大。

6. 如果有人恶意创建非法连接,怎么解决。

7. 分布式事务:XA,2PC,3PC,TCC

XA协议

XA则规范了TM与RM之间的通信接口,在TM与多个RM之间形成一个双向通信桥梁,从而在多个数据库资源下保证ACID四个特性。目前知名的数据库,如Oracle, DB2,mysql等,都是实现了XA接口的,都可以作为RM。

2PC

在处理分布式事务时分为两个阶段:voting(投票阶段,有的地方会叫做prepare阶段)和commit阶段。

3PC

协议在协调者和参与者中都引入 超时机制,并且把两阶段提交协议的第一个阶段拆分成了两步:询问,然后再锁资源,最后真正提交。三阶段提交的三个阶段分别为:can_commit,pre_commit,do_commit。

2PC和3PC的区别:

相对于2PC,3PC主要解决的单点故障问题,并减少阻塞。一旦参与者无法及时收到来自协调者的信息之后,他会默认执行commit。而不会一直持有事务资源并处于阻塞状态。无论是二阶段提交还是三阶段提交都无法彻底解决分布式的一致性问题。世上只有一种一致性算法,那就是Paxos,所有其他一致性算法都是Paxos算法的不完整版

TCC

Try阶段:完成所有业务检查(一致性),预留业务资源(准隔离性)
Confirm阶段:确认执行业务操作,不做任何业务检查, 只使用Try阶段预留的业务资源。要满足幂等性。
Cancel阶段:取消Try阶段预留的业务资源。

TCC与XA两阶段提交二者之间的对比 :

TCC是业务的分布式事务,最终一致性,不会出现长事务的锁风险,try是本地事务,锁定资源后就提交事务,confirm/cancel也是本地事务,可以直接提交事务,所以多个短事务不会出现长事务的风险。

分布式事务:XA,2PC,3PC,TCC_小英雄-CSDN博客_2pc 3pc tcc

8. 什么是一致性 hash。

假设:我们增加了一台缓存服务器,那么缓存服务器的数量就由4台变成了5台。那么原本hash(a.png) % 4 = 2 的公式就变成了hash(a.png) % 5 = ? , 可想而知这个结果肯定不是2的,这种情况带来的结果就是当服务器数量变动时,所有缓存的位置都要发生改变!换句话说,当服务器数量发生改变时,所有缓存在一定时间内是失效的,当应用无法从缓存中获取数据时,则会向后端数据库请求数据。

一致性Hash算法也是使用取模的方法,只是,刚才描述的取模法是对服务器的数量进行取模,而一致性Hash算法是对2^32取模。一致性Hash算法对于节点的增减都只需重定位环空间中的一小部分数据,具有较好的容错性和可扩展性。

想要深入理解可以看:

一致性哈希算法的领悟_击水三千里的专栏-CSDN博客_一致性哈希算法,在扩容和缩容、宕机情况下有什么优点?

9. 什么是 restful,讲讲你理解的 restful。

10. 如何设计建立和保持 100w 的长连接。

并发编程之Disruptor框架介绍和高阶运用_击水三千里的专栏-CSDN博客_disruptor框架使用

11. 如何防止缓存雪崩。

12. 解释什么是 MESI 协议(缓存一致性)。

13. 说说你知道的几种 HASH 算法,简单的也可以。

14. 什么是 paxos 算法。

15. 什么是 zab 协议。

整个ZAB协议主要包括消息广播和崩溃恢复两个过程,进一步可以分为三个阶段,分别是:

发现 Discovery
同步 Synchronization
广播 Broadcast
组成ZAB协议的每一个分布式进程,都会循环执行这三个阶段,将这样一个循环称为一个主进程周期。

16. 一个在线文档系统,文档可以被编辑,如何防止多人同时对同一份文档进行编辑更新。

17. 线上系统突然变得异常缓慢,你如何查找问题。

18. 说说你平时用到的设计模式。

19. Dubbo 的原理,数据怎么流转的,怎么实现集群,负载均衡,服务注册和发现。重试转发,快速失败的策略是怎样的。

20. 一次 RPC 请求的流程是什么。

21. 异步模式的用途和意义。

22. 缓存数据过期后的更新如何设计。

23. 编程中自己都怎么考虑一些设计原则的,比如开闭原则,以及在工作中的应用。

24. 设计一个社交网站中的“私信”功能,要求高并发、可扩展等等。画一下架构图。

25. MVC 模式,即常见的 MVC 框架。

26. 聊了下曾经参与设计的服务器架构。

27. 应用服务器怎么监控性能,各种方式的区别。

28. 如何设计一套高并发支付方案,架构如何设计。

如何设计一个秒杀系统_击水三千里的专栏-CSDN博客

29. 如何实现负载均衡,有哪些算法可以实现。

30. Zookeeper 的用途,选举的原理是什么。

31. Mybatis 的底层实现原理。

MyBatis底层就是JDBC   所以他的核心就是配置文件  :1:全局配置文件 (配置数据源 事务运行时信息)2:映射文件(执行statement的相关信息,包括SQL语句,输入参数,输出结果)MyBatis把全局配置文件加载到内容中 构建出SqlSessionFactory    ,这个工厂的作用相当于生产对象
生产SqlSession。SqlSession   :它是一个面向程序员的接口,可以操作数据库。 接口有一个默认实现DefaultSqlSession。
在SqlSession   中有一个executor 执行器。  SqlSession   本身不能操作数据库 需要通过这个执行器去操
作。有2个实现 一个叫做基本执行器,还有一个缓存执行器
(默认)。 MappedStatement:封装了执行Statement信息,包括SQL语句 输入参数,输出结果。由它去操作数
据库。输入输出参数类型:1:基本类型2:自定义类型3:hashmap根据源码:看到Sqlsession内部并不能直接操作数据库。而是利用内部的一个执行器去操作数据库。执行器执行
的时候会去执行MappedStatement
到最后才去真正执行数据库。

32. 请思考一个方案,设计一个可以控制缓存总体大小的自动适应的本地缓存。

33. 请思考一个方案,实现分布式环境下的 countDownLatch。

34. 后台系统怎么防止请求重复提交。

用隐藏表单记录token属性。当提交表单后,应用程序会比较隐藏域中的值和Session域中的标志号(比较比较之后会清除当前用户Session中的token),如果相同就处理表单数,如果不相同就会忽略表单请求同时生成新的token存入Session中。当重复提交表单时,当前Session域中会不存在相应的表单标识号。

详细介绍见:防止重复提交的前后台实现_不给失败找借口,只给成功想办法-CSDN博客

35. 如何看待缓存的使用(本地缓存,集中式缓存),简述本地缓存和集中式缓存和优缺点。本地缓存在并发使用时的注意事项。

36. 描述一个服务从发布到被消费的详细过程。

37. 讲讲你理解的服务治理。

38. 如何做到接口的幂等性。

接口幂等性,只要保证接口内的逻辑不涉及接口外的对象状态累积或变迁即可。譬如说需求是:
当用户点击赞同时,将答案的赞同数量+1。
改为:
当用户点击赞同时,确保答案赞同表中存在一条记录,用户、答案。
赞同数量由答案赞同表统计出来

39.集群部署时的分布式session如何实现?

(1)tomcat + redis

(2)spring session + redis

(3)RedisSession jar包

40.如果让你设计一个消息中间件,你会怎么做?

生产消费模型以及核心数据结构
可以先允许数据写入内存作为一个缓冲,然后每隔几秒再把数据刷入磁盘文件中,数据写入磁盘文件之后,是不是要有相应的一些metadata来标识这个数据的offset偏移量,和内置的唯一id。一个queue里的数据,是会均匀分配给消费者的各个实例

算法

1. 10 亿个数字里里面找最小的 10 个。

先根据数据值/机器数后的商划分到不同的机器上,最好可以让数据划分后一次读入内存这样不同的机器负责处
理不同的数值范围。得到结果后,对最小的数据范围的机器进行堆排序(构建小顶堆)。

2. 有 1 亿个数字,其中有 2 个是重复的,快速找到它,时间和空间要最优。

原理:把数字值直接映射到数组下标(时间最优),这里重复的数字只有两次,为了空间最优,就用bit来表示(只有0和1),1byte=8bit,一个byte可以存储8个数字的计数。
所以建立数组 byte[] bucket=new byte[(最大值-最小值)/8+1];

public class Test{public static void main(String[] args){long time=new Date().getTime();int[] arr=new int[100000000];//1亿长度for(int i=0;i<arr.length;i++){arr[i]=i+1;}arr[99999999]=2020;int min=arr[0];int max=arr[0];for(int i=0;i<arr.length;i++){if(arr[i]<min)min=arr[i];if(arr[i]>max)max=arr[i];}byte[] bucket=new byte[(max-min)/8+1];for(int i=0;i<arr.length;i++){int num=arr[i];int j=(num-min)/8;int k=(num-min)%8;if(((bucket[j]>>k)&1)>0){//重复了System.out.println("Number of repeats:"+num);break;}else{bucket[j]|=(1<<k);}}long time2=new Date().getTime();System.out.println("millisecond:"+(time2-time));}
}

3. 2 亿个随机生成的无序整数,找出中间大小的值。

首先我们将 int 划分为 2^16 个区域,然后读取数据统计落到各个区域里的数的个数,之
后我们根据统计结果就可以判断中位数落到那个区域,同时知道这个区域中的第几大数刚好是中位数。然后第二次扫描我们只统计落在这个区域中的那些数就可以了。

4. 给一个不知道长度的(可能很大)输入字符串,设计一种方案,将重复的字符排重。

5. 遍历二叉树。

6. 有 3n+1 个数字,其中 3n 个中是重复的,只有 1 个是不重复的,怎么找出来。

7. 写一个字符串反转函数。

8. 常用的排序算法,快排,归并、冒泡。 快排的最优时间复杂度,最差复杂度。冒泡排序的优化方案。

排序法

最差时间分析 平均时间复杂度 稳定度 空间复杂度
冒泡排序 O(n2) O(n2) 稳定 O(1)
快速排序 O(n2) O(n*log2n) 不稳定 O(log2n)~O(n)
选择排序 O(n2) O(n2) 不稳定 O(1)
二叉树排序 O(n2) O(n*log2n) 不一顶 O(n)

插入排序

O(n2) O(n2) 稳定 O(1)
堆排序 O(n*log2n) O(n*log2n) 不稳定 O(1)
归并排序 O(n*log2n) O(n*log2n) 稳定 O(n)
public void sortArray(int[] array){int temp;for(int i=0; i<array.length; i++){boolean isSorted = true;for(int j=0; j<array.length-i-1; j++){if(array[j] > array[j+1]){temp = array[j];array[j] = array[j+1];array[j+1] = temp;isSorted = false;}}if(isSorted){break;}}
}

定义了一个boolean类型的isSorted变量,用来判断往后的循环当中,数组是否已经是有序的,每一轮循环都会设置其值为true,当有元素对调位置时,就将isSorted的值设置为false,表示该数组还不是有序数组。每一轮都要判断isSorted的值,如果判断当前一轮操作没有元素有位置调换,那么可以提前结束所有的循环

9. 二分查找的时间复杂度,优势。

10. 一个已经构建好的 TreeSet,怎么完成倒排序。

11.md5加密的原理

MD5是输入不定长度信息,输出固定长度128-bits的算法。经过程序流程,生成四个32位数据,最后联合起来成为
一个128-bits散列。基本方式为,求余、取余、调整长度、与链接变量进行循环运算。得出结果。

MD5值算法原理 - 你好中国 - 博客园

12.给一台普通PC,2G内存,要求处理一个包含40亿个不重复并且没有排过序的无符号的int整数,给出一个整数,问如果快速地判断这个整数是否在文件40亿个数据当中?

问题思考:
40亿个int占(40亿*4)/1024/1024/1024 大概为14.9G左右,很明显内存只有2G,放不下,因此不可能将这
40亿数据放到内存中计算。要快速的解决这个问题最好的方案就是将数据搁内存了,所以现在的问题就在如何
在2G内存空间以内存储着40亿整数。一个int整数在java中是占4个字节的即要32bit位,如果能够用一个bit
位来标识一个int整数那么存储空间将大大减少,算一下40亿个int需要的内存空间为40亿/8/1024/1024大概
为476.83 mb,这样的话我们完全可以将这40亿个int数放到内存中进行处理。具体思路:1个int占4字节即4*8=32位,那么我们只需要申请一个int数组长度为 int tmp[1+N/32]即可存储完这些
数据,其中N代表要进行查找的总数,tmp中的每个元素在内存在占32位可以对应表示十进制数0~31,所以可得
到BitMap表:tmp[0]:可表示0~31tmp[1]:可表示32~63tmp[2]:可表示64~95.......那么接下来就看看十进制数如何转换为对应的bit位:假设这40亿int数据为:6,3,8,32,36,......,那么具体的BitMap表示为:00000000000000000000000101001001
00000000000000000000000000010000如何判断int数字在tmp数组的哪个下标,这个其实可以通过直接除以32取整数部分,例如:整数8除以32取整
等于0,那么8就在tmp[0]上。另外,我们如何知道了8在tmp[0]中的32个位中的哪个位,这种情况直接mod上
32就ok,又如整数8,在tmp[0]中的第8 mod上32等于8,那么整数8就在tmp[0]中的第9个bit位(从右边数
起)。解法二:
Bloom Filter 原理下面来分析下它的实现原理。官方的说法是:它是一个保存了很长的二进制向量,同时结合 Hash 函数实现的。对写入的数据做 H 次 hash 运算定位到数组中的位置,同时将数据改为 1 。当有数据查询时也是同样的方式定
位到数组中。 一旦其中的有一位为 0 则认为数据肯定不存在于集合,否则数据可能存在于集合中。布隆过滤有以下几个特点:
只要返回数据不存在,则肯定不存在。
返回数据存在,但只能是大概率存在。
同时不能清除其中的数据。它不适合那些"零误判"的应用场合.在能容忍低误判的应用场景下,布隆过滤器通过极少的误判换区了存储空间的极大节省.

拜托,面试官别问我「布隆」了

13. 在2.5亿个整数中找出不重复的整数,注,内存不足以容纳这2.5亿个整数

解法一:将bit-map扩展一下,采用2-Bitmap(每个数分配2bit,00表示不存在,01表示出现一次,10表示多
次,11无意义)进行,共需内存2^32 * 2 bit=1 GB内存,还可以接受。然后扫描这2.5亿个整数,查看Bitmap
中相对应位,如果是00变01,01变10,10保持不变。所描完事后,查看bitmap,把对应位是01的整数输出即可。或者我们不用2bit来进行表示,我们用两个bit-map即可模拟实现这个2bit-map,都是一样的道理。解法二:根据数字hash,划分小文件。然后在小文件中找出不重复的整数,并排序。然后再进行归并,注意去除重复的元素。

BitMap算法_皮皮blog-CSDN博客_bitmap

14.给定 a、b 两个文件,各存放 50 亿个 URL,每个 URL 各占 64B,内存限制是 4G。请找出 a、b 两个文件共同的 URL。

每个 URL 占 64B,那么 50 亿个 URL 占用的空间大小约为 320GB。5, 000, 000, 000 _ 64B ≈ 5GB _ 64
= 320GB 由于内存大小只有 4G,因此,我们不可能一次性把所有 URL 加载到内存中处理。对于这种类型的题
目,一般采用分治策略 ,即:把一个文件中的 URL 按照某个特征划分为多个小文件,使得每个小文件大小不
超过 4G,这样就可以把这个小文件读到内存中进行处理了。首先遍历文件 a,对遍历到的 URL 求 hash(URL) % 1000 ,根据计算结果把遍历到的 URL 存储到 a0, a1,
a2, ..., a999,这样每个大小约为 300MB。使用同样的方法遍历文件 b,把文件 b 中的 URL 分别存储到文
件 b0, b1, b2, ..., b999 中。这样处理过后,所有可能相同的 URL 都在对应的小文件中,即 a0 对应
b0, ..., a999 对应 b999,不对应的小文件不可能有相同的 URL。那么接下来,我们只需要求出这 1000 对
小文件中相同的 URL 就好了。接着遍历 ai( i∈[0,999] ),把 URL 存储到一个 HashSet 集合中。然后遍历 bi 中每个 URL,看在
HashSet 集合中是否存在,若存在,说明这就是共同的 URL,可以把这个 URL 保存到一个单独的文件中。

如何从 100 亿 URL 中找出相同的 URL?

MySQL

1. 行转列

姓名       课程       分数

---------- ---------- -----------

张三       语文        74

张三       数学        83

张三       物理        93

李四       语文        74

李四       数学        84

李四       物理        94

SELECT 姓名,max(CASE 课程 WHEN'语文' THEN 分数 ELSE 0 END) 语文,max(CASE 课程 WHEN'数学' THEN 分数 ELSE 0 END) 数学,max(CASE 课程 WHEN'物理' THEN 分数 ELSE 0 END) 物理
FROM tb
GROUP BY 姓名姓名        语文        数学        物理
---------- ----------- ----------- -----------
李四        74          84          94
张三        74          83          93

2. MySQL存储引擎- MyISAM与InnoDB区别

第一个重大区别是:InnoDB的主索引的数据文件本身就是索引文件。从上文知道,MyISAM主索引的索引文件和数据
文件是分离的,索引文件仅保存数据记录的地址。而在InnoDB中,表数据文件本身就是按B+Tree组织的一个索引
结(index=data),这棵树的叶节点data域保存了完整的数据记录。这个索引的key是数据表的主键,因此InnoDB
表数据文件本身就是主索引。第二个重大区别是:MyISAM类型不支持事务处理等高级处理,而InnoDB类型支持事务处理与外键和行级锁。MyISAM
类型的表强调的是性能,其执行速度比InnoDB类型更快,但是不提供事务支持,而InnoDB提供事务支持以及外部
键等高级数据库功能。 所以MyISAM往往就容易被人认为只适合在小项目中使用第三个区别是:InnoDB的辅助索引data域存储相应记录主键的值而不是地址。而MyISAM的辅助索引和主索引没
有多大区别

不同存储引擎的索引实现方式对于正确使用和优化索引都非常有帮助,例如知道了InnoDB的索引实现后,就很容易明白为什么不建议使用过长的字段作为主键,因为所有辅助索引都引用主索引,过长的主索引会令辅助索引变得过大。再例如,用非单调的字段作为主键在InnoDB中不是个好主意,因为InnoDB数据文件本身是一颗B+Tree,非单调的主键会造成在插入新记录时数据文件为了维持B+Tree的特性而频繁的分裂调整,十分低效,而使用自增字段作为主键则是一个很好的选择。

3,数据库隔离级别有哪些,各自的含义是什么,Mysql默认的隔离级别是是什么

InnoDB使用多版本并发控制来获得高并发性,并且实现了sql标准的4种隔离级别,分别是:
1.未提交读:在未提交读级别,事务中的修改,即使没有提交,对其他事务也都是可见的2.提交读(Read committed):大多数数据库系统的默认隔离级别都是提交读(但Mysql不是)一个事务开始
时,只能“看见”已经提交的事务所做的修改",该隔离级别有时也叫"不可重复度"3.可重复读:可重复读解决了脏读的问题。该级别保证了在同一个事务中多次读取同样记录的结果是一致的。但是
理论上,可重复读隔离级别还是无法解决当某个事务在读取某个范围内的记录时,另外一个事务中又在该范围插入
了新的记录,当之前的事务再次读取该范围的记录时,会产生幻行。可重复读是MySQL的默认事务隔离级别。4.可串行化:可串行化是最高的隔离级别。它通过强制事务串行执行,避免了前面所说的幻读问题。简单来说,可
串行化会在读取的每一行数据上都加上锁,所以可能导致大量的超时和锁争用问题

4.高并发下,如何做到安全的修改同一行数据,乐观锁和悲观锁是什么,INNODB的行级锁有哪2种,解释其含义

InnoDB实现了以下两种类型的行锁。共享锁(S):允许一个事务去读一行,阻止同一Session其他事务获得相同数据集的排他锁。当事务同时增加共享锁时候,事务的更新必须等待先执行的事务 commit 后才行,如果同时并发太大可能很容易造成死锁排他锁(X):允许获得排他锁的事务更新数据,阻止同一Session其他事务取得相同数据集的共享读锁和排他写
锁。共享锁(S):SELECT * FROM table_name WHERE ... LOCK IN SHARE MODE
排他锁(X):SELECT * FROM table_name WHERE ... FOR UPDATE另外,为了允许行锁和表锁共存,实现多粒度锁机制,InnoDB还有两种内部使用的意向锁(Intention
Locks),这两种意向锁都是表锁。
意向共享锁(IS):事务打算给数据行加行共享锁,事务在给一个数据行加共享锁前必须先取得该表的IS锁。
意向排他锁(IX):事务打算给数据行加行排他锁,事务在给一个数据行加排他锁前必须先取得该表的IX锁InnoDB行锁是通过给索引上的索引项加锁来实现的,这一点与Oracle不同,后者是通过在数据块中对相应数据行
加锁来实现的。InnoDB这种行锁实现特点意味着:只有通过索引条件检索数据,InnoDB才使用行级锁,否则,
InnoDB将使用表锁!
在实际应用中,要特别注意InnoDB行锁的这一特性,不然的话,可能导致大量的锁冲突,从而影响并发性能锁的算法
Record Lock :单个记录上的锁。
Gap Lock:间隙锁,锁定一个范围,但不包含记录本身。
Next-key Lock: 锁定一个范围和本身 Record Lock + Gap Lock。
例如一个索引有10,11,13,20这4个值,那么索引可能被Next-key Locking的区间为:
(- ∞,10), [10,11) , [11,13), [13,20), [20,+ ∞)
Next-key Lock为了解决幻读问题

5.SQL优化的一般步骤是什么,怎么看执行计划,如何理解其中各个字段的含义,索引的原理?

6.数据库会死锁吗,举一个死锁的例子,mysql怎么解决死锁

事务A等待事务B,同时事务B等待事务A,会产生死锁。
Innodb有死锁检测进程,如果检测到死锁,会马上抛出异常并回滚一个事务(另一个继续执行)死锁的关键在于:两个(或以上)的Session加锁的顺序不一致。
那么对应的解决死锁问题的关键就是:让不同的session加锁有次序

7.什么是 B+树,B-树,列出实际的使用场景。

在讲B+树之前必须先了解二叉查找树、平衡二叉树(AVLTree)和多路平衡查找树(B-Tree),B+树即由这些
树逐步优化而来。B+Tree相对于B-Tree有几点不同:
1.B+非叶节点不保存数据相关信息, 只保存关键字和子节点的引用
2.B+叶子节点是顺序排列的, 并且相邻节点具有顺序引用的关系(存在一个链指针)
3.B+关键字对应的数据保存在叶子节点中
4.B+节点关键字搜索采用左闭合区间(a<= x < b)为什么使用B+Tree
红黑树等数据结构也可以用来实现索引,但是文件系统及数据库系统普遍采用B-Tree作为索引结构,一般来说,索引本身也很大,不可能全部存储在内存中,因此索引往往以索引文件的形式存储的磁盘上。这样的
话,索引查找过程中就要产生磁盘I/O消耗,相对于内存存取,I/O存取的消耗要高几个数量级,所以评价一个数据结构作为索引的优劣最重要的指标就是在查找过程中磁盘I/O操作次数的渐进复杂度。根据B+Tree的定义,可知检索一次最多需要访问h个节点。数据库系统的设计者巧妙利用了磁盘预读原理,将一个节点的大小设为等于一个页,这样每个节点只需要一次I/O就可以完全载入。(Innodb的数据页是16K,1.2.x支持8K,4K压缩页)。每次新建节点时,直接申请一个页的空间,这样就保证一个节点物理上也存储在一个页里,加之计算机存储分配都是按页对齐的,就实现了一个node只需一次I/O。B-Tree中一次检索最多需要h-1次I/O(根节点常驻内存),渐进复杂度为O(h)=O(logdN)。而红黑树这种结构,h明显要深的多。由于逻辑上很近的节点(父子)物理上可能很远,无法利用局部性,所以红黑树的I/O渐进复杂度也为O(h),效率明显比B-Tree差很多。为什么使用B+Tree
B+树是B-树的变种(PLUS版)多路绝对平衡查找树, 他拥有B-树的优势
B+树扫库、 表能力更强(只需要扫描关键字和引用)
B+树的磁盘读写能力更强(B+树的根节点和支节点不保存数据区,所以根节点和支节点同样大小的情况下,保存的关键字要比B-树要多)
B+树的排序能力更强(叶子几点顺序排列)
B+树的查询效率更加稳定(和数据在叶子节点有关)

什么是 B+树,B-树

B-树

B+树

8、 Select Count (*)和Select Count(1)以及Select Count(column)区别

count(*) 包括了所有的列,相当于行数,在统计结果的时候,不会忽略列值为NULL ;

count(1) 1并不是表示第一个字段,而是表示一个固定值。其实就可以想成表中有这么一个字段,这个字段就是固定值1。就是计算一共有多少个1,在统计结果的时候,不会忽略列值为NULL 。

count(字段) 会统计该字段在表中出现的次数,忽略字段为NULL值的记录数。

一般情况下,Select Count (*)和Select Count(1)两着返回结果是一样的
假如表沒有主键(Primary key), 那么count(1)比count(*)快,
如果有主键的話,那主键作为count的条件时候count(主键)最快
如果你的表只有一个字段的话那count(*)就是最快的
count(*) 跟 count(1) 的结果一样,都包括对NULL的统计,而count(column) 是不包括NULL的统计

https://blog.csdn.net/lingduo24/article/details/87621363

9、唯一索引,可以在索引列插入多个null吗

1,唯一索引可在索引列插入多次null
2,适用于表中的一些业务列,不能出现重复,但可以插入空值,比如用户表的身份证号码

10、写出一条sql查询出student(id,name)表中name相同id连续的三条记录

SELECTa.id,b.id,c.id
FROMstudent a,student b,student c
WHEREa.id - b.id = 1
AND b.id - c.id = 1
AND a.name= b.name
AND b.name= c.name

正在上传…重新上传取消

11、SQL语句关键字的执行顺序是什么

这张图与 SQL 查询的语义有关,让你知道一个查询会返回什么,并回答了以下这些问题:

  • 可以在 GRROUP BY 之后使用 WHERE 吗?(不行,WHERE 是在 GROUP BY 之前!)

  • 可以对窗口函数返回的结果进行过滤吗?(不行,窗口函数是 SELECT 语句里,而 SELECT 是在 WHERE 和 GROUP BY 之后)

  • 可以基于 GROUP BY 里的东西进行 ORDER BY 吗?(可以,ORDER BY 基本上是在最后执行的,所以可以基于任何东西进行 ORDER BY)

  • LIMIT 是在什么时候执行?(在最后!)

但数据库引擎并不一定严格按照这个顺序执行 SQL 查询,因为为了更快地执行查询,它们会做出一些优化,这些问题会在以后的文章中解释。

  • 如果你想要知道一个查询语句是否合法,或者想要知道一个查询语句会返回什么,可以参考这张图;

  • 在涉及查询性能或者与索引有关的东西时,这张图就不适用了。

SQL 查询语句总是先执行 SELECT?你们都错了

12、UUID做主键为什么查询和插入效率比自增主键低

UUID 太长了、占用空间大,作为主键性能太差了;更重要的是,UUID 不具有有序性,会导致 B+ 树索引在写的时候有过多的随机写操作(连续的 ID 可以产生部分顺序写),还有,由于在写的时候不能产生有顺序的 append 操作,而需要进行 insert 操作,将会读取整个 B+ 树节点到内存,在插入这条记录后会将整个节点写回磁盘,这种操作在记录占用空间比较大的情况下,性能下降明显

中间件

1.Dubbo有哪些均衡策略,和集群模式

均衡策略

1、随机(缺省),按权重设置随机概率。
在一个截面上碰撞的概率高,但调用量越大分布越均匀,而且按概率使用权重后也比较均匀,有利于动态调整提供者权重。2、轮循,按公约后的权重设置轮循比率。
存在慢的提供者累积请求问题,比如:第二台机器很慢,但没挂,当请求调到第二台时就卡在那,久而久之,所有请求都卡在调到第二台上。3、最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差。
使慢的提供者收到更少请求,因为越慢的提供者的调用前后计数差会越大。4、一致性Hash,相同参数的请求总是发到同一提供者。
当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引起剧烈变动。

集群容错模式:

1、失败自动切换,当出现失败,重试其它服务器。(缺省)
通常用于读操作,但重试会带来更长延迟。
可通过retries="2"来设置重试次数(不含第一次,默认就是2)2、快速失败,只发起一次调用,失败立即报错。
通常用于非幂等性的写操作,比如新增记录。3、失败安全,出现异常时,直接忽略。
通常用于写入审计日志等操作。4、失败自动恢复,后台记录失败请求,定时重发。
通常用于消息通知操作。5、并行调用多个服务器,只要一个成功即返回。
通常用于实时性要求较高的读操作,但需要浪费更多服务资源。
可通过forks="2"来设置最大并行数。6、广播调用所有提供者,逐个调用,任意一台报错则报错。(2.1.0开始支持)
通常用于通知所有提供者更新缓存或日志等本地资源信息。
重试次数配置如:(failover集群模式生效)

高并发下接口幂等性解决方案

1、为什么要有Dubbo的原因

各个团队的服务提供方就不要各自实现一套序列化、反序列化、网络框架、连接池、收发线程、超时处理、状态机等“业务之外”的重复技术劳动,造成整体的低效。

2.MQ分布式系统事务一致性解决方案

分布式系统事务一致性解决方案-InfoQ

3.redis分布式缓存

分布式缓存技术redis学习系列(三)——redis高级应用(主从、事务与锁、持久化)_javaloveiphone的专栏-CSDN博客

http://blog.csdn.net/javaloveiphone/article/details/52352894

4.redis和memcached的区别

1、Redis和Memcache都是将数据存放在内存中,都是内存数据库。不过memcache还可用于缓存其他东西,例如图片、视频等等;
2、Redis不仅仅支持简单的k/v类型的数据,同时还提供list,set,hash等数据结构的存储;
3、虚拟内存--Redis当物理内存用完时,可以将一些很久没用到的value 交换到磁盘;
4、过期策略--memcache在set时就指定,例如set key1 0 0 8,即永不过期。Redis可以通过例如expire 设定,例如expire name 10;
5、分布式--设定memcache集群,利用magent做一主多从;redis可以做一主多从。都可以一主一从;
6、存储数据安全--memcache挂掉后,数据没了;redis可以定期保存到磁盘(持久化);
7、灾难恢复--memcache挂掉后,数据不可恢复; redis数据丢失后可以通过aof恢复;
8、Redis支持数据的备份,即master-slave模式的数据备份;
9、应用场景不一样:Redis出来作为NoSQL数据库使用外,还能用做消息队列、数据堆栈和数据缓存等;Memcached适合于缓存SQL语句、数据集、用户临时性数据、延迟查询数据和session等。

5、Zookeeper的临时节点是否有子节点

没有

6、Dubbo 为什么要选择使用zookeeper做为注册中心,而不用redis?

zookeeper的优势:
1.当提供程序意外停止时,注册表服务器可以自动删除其信息。
2.注册表服务器重新启动时,可以自动恢复所有注册数据和订阅请求。
3.会话过期后,可以自动恢复所有注册数据和订阅请求。redis存在的问题?
redis是通过发布订阅模式完成消息的通知 但是存在几个问题:1.服务的非自然下线需要监护中心来维护
2.redis做注册中心服务器时间必需同步,否则出现时间不对被强制过期(删除key)!
3.zookeeper支持监听,redis不支持,因此需要客户端启动多个线程进行订阅监听,对服务器有一定压力!

Java中高级面试题总览(一)相关推荐

  1. Java中高级面试题 -- 数十道题含答案

    Java中高级面试题 一.基础知识: 1)集合类:List和Set比较,各自的子类比较(ArrayList,Vector,LinkedList:HashSet,TreeSet): ArrayList ...

  2. Java中高级面试题部分答案解析

    Java中高级面试题部分答案解析 List和Set比较,各自的子类比较 对比一:Arraylist与LinkedList的比较 1.ArrayList是实现了基于动态数组的数据结构,因为地址连续,一旦 ...

  3. Java中高级面试题部分答案解析(3)

    点击上方"Java知音",选择"置顶公众号" 技术文章第一时间送达! 知音专栏 Javaweb练手项目源码下载 常用设计模式完整系列篇 100套IT类简历模板下 ...

  4. java中高级面试题整理

    java中高级面试题整理                  问题                                                                     ...

  5. java面试题(java中高级面试题及答案)

    [java面试题] 1.Collections.sort排序内部原理 在Java6Arrays.sort()和Collections.sort()中使用MergeSort,在Java7中,内部实现被T ...

  6. 100道Java中高级面试题汇总+详细拆解

    出自:Java面试题精选 1-10期 [10期]Redis 面试常见问答 [09期]说说hashCode() 和 equals() 之间的关系? [08期]说说Object类下面有几种方法呢? [07 ...

  7. 【Java从0到架构师(1),Java中高级面试题总结(全面)

    JSP 九大内置对象 MySQL 基础 + 多表查询 [Java从0到架构师]MySQL 基础 MySQL MySQL 的使用步骤 数据库的内部存储细节 GUI 工具 SQL 语句 DDL 语句 DD ...

  8. 阿里最新秋招面经,腾讯/美团/字节1万道Java中高级面试题

    又是一年过去了,职场的积雪还没有消融,又迎来了一次大考.疫情还没完全过去,大家强打起精神,相互问好致意,眼角却满是疲惫- 企业调薪.裁员.组织架构调整等等,坏消息只多不少,最近也有很多来咨询跳槽的朋友 ...

  9. 阿里最新春招面经,腾讯 / 美团 / 字节 1 万道 Java 中高级面试题

    我梳理了各个大厂春秋招面经分享,分享上万道面试题及答案,从实习生到开发 1-10 年的简历模板,面试过程的文档教程! 阿里常问面试题(1-5 年经验) String,StringBuffer,Stri ...

最新文章

  1. python中编写无参数decorator
  2. 项目管理一般知识:项目生命周期
  3. 计算机管理未指定错误,win10系统计算机管理打不开显示有“未指定的错误”的方案介绍222...
  4. C语言关键字static与extern的详细解释
  5. 彻底搞懂 Scrapy 的中间件
  6. close_wait过多服务器无响应,记一次大量CLOSE_WAIT连接导致的服务宕机
  7. metro风格后台管理效果
  8. 锁分段技术、ConcurrentHashMap、扩容
  9. 结构化数据传输协议xml、json、protobuf比较
  10. Javascript倒计时 支持自定义样式
  11. 按键精灵post请求_[教程] 以本论坛为例,手把手教你使用按键精灵POST登陆网页...
  12. NFC bcm2079x驱动学习 .
  13. 木瓜移动每日资讯0602:“店小秘”宣布完成1.35亿元人民币B+轮融资
  14. 白帽子挖洞第II篇作业--xray+fofa主动扫描
  15. 微型计算机显示器接口,微型计算机接口技术8-2LED显示器接口-Read.PPT
  16. 微信小程序-云开发上传文件、图片
  17. 足球一代又一代得青春
  18. python中fill函数_在figu中旋转matplotlib的fill函数
  19. 蓝代斯克和玖道在华设立合资企业
  20. 混淆电路——混淆电路原理

热门文章

  1. 低成本家庭KTV方案
  2. 怎么把群晖个人用户空间相片映射到公共空间/photo
  3. Hadoop Yarn RPC远程命令执行
  4. 天创与阿里云合作 推出“易联”物联网设备运营管理云平台
  5. 《七周七数据库》一一2.4 第3天:全文检索和多维查询
  6. 自定义属性的设置,获取和移除
  7. wordContrl word文档管理工具
  8. JavaScript-rem布局
  9. GORM 预加载和自引用
  10. 荔枝FM架构师刘耀华:异地多活IDC机房架构 - 极客头条 - CSDN.NET