当前位置:   article > 正文

Java面试题_如果在homecontroller中定义了一个add(int first,int second)的方

如果在homecontroller中定义了一个add(int first,int second)的方法,那么以下url

有两个字符串String s1 = “38948598490”;
String s2 = “398758476”;
可能超出了long的范围,要求相加并返回字符串的值。

解答:

    char[] a1 = s1.toCharArray();
	char[] a2 = s2.toCharArray();
	StringBuilder sb = new StringBuilder();
	int len1 = a1.length;
	int len2 = a2.length;
	
	int temp = 0;
	int i;
	for (i = 0; i < len1 && i < len2; i++) {
		int left = Integer.valueOf(a1[len1 - i - 1] + "");
		int right = 0;
		right = Integer.valueOf(a2[len2 - i - 1] + "");
		left = left + right + temp;
		temp = left / 10;
	
		int h = left % 10;
		sb.append(h + "");
	}
	if (len1 != len2) {
		if (i + 1 == len1) {
			for (i = len1; i < len2; i++) {
				int t = Integer.valueOf(a2[len2 - i - 1] + "");
				t = t + temp;
				temp = t / 10;
				
				int h = t % 10;
				sb.append(h + "");
			}
		} else {
			for (i = len2; i < len1; i++) {
				int t = Integer.valueOf(a1[len1 - i - 1] + "");
				t = t + temp;
				temp = t / 10;
				
				int h = t % 10;
				sb.append(h + "");
			}
		}
	}
	
	String s = sb.toString();
	sb = new StringBuilder();
	int l = s.length();
	for (int j = l - 1; j >= 0; j--) {
		sb.append(s.charAt(j) + "");
	}
	return sb.toString();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47

做的时候没有考虑周到,做错了。

2、JVM加载class文件的原理机制?
JVM中类的装载是由类加载器(ClassLoader)和它的子类来实现的。Java程序需要使用某个类时,JVM会确保这个类已经被加载、连接(验证、准备和解析)和初始化。类的加载是由类加载器完成的,类加载器包括:根加载器(BootStrap)、扩展加载器(Extension)、系统加载器(System)和用户自定义类加载器(java.lang.ClassLoader的子类)。

3、引发stackoverflowerror的原因
内存不够;递归调用

4、Error和Exception的区别
Error(错误)是系统中的错误,程序员是不能改变的和处理的,一般是指与虚拟机相关的问题。
Exception(异常)表示程序可以处理的异常,可以捕获且可能恢复。遇到这类异常,应该尽可能处理异常,使程序恢复运行,而不应该随意终止异常。

5、java中volatile能修饰数组吗?
可以,java源码中有

6、volatile能使一个非原子操作变成原子操作吗?
不能,volatile保证变量的可见性。保证原子操作用synchonized或lock

7、java中weakReference和softReference的区别?
SoftReference 在jvm即将抛出oom的时候,垃圾回收器才会将该引用对象进行回收,避免了系统内存溢出的情况。非常适合实现内存敏感的缓存,例如加载图片的时候,bitmap缓存机制。
WeakReference当垃圾回收器扫描到弱引用的对象的时候,不管内存空间是否足够,都会直接被垃圾回收器回收。不过也不用特别担心,垃圾回收器是一个优先级比较低的现场,因此不一定很快可以发现弱引用的对象。

8、hashSet、hashMap的内部如何工作的?
equals方法相等,那么hashCode方法也必须相等。
equals方法不相等,那么hashCode方法也可以相等。

hashMap的结构是数组和链表。
利用key的hashCode重新hash计算出当前对象的元素在数组中的下标;
存储时,如果出现hash值相同的key,此时有两种情况。(1)如果key相同,则覆盖原始值;(2)如果key不同(出现冲突),则将当前的key-value放入链表中;
获取时,直接找到hash值对应的下标,在进一步判断key是否相同,从而找到对应值。

9、依赖注入和控制反转
Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。
依赖注入”明确描述了“被注入对象依赖IoC容器配置依赖对象”。是控制反转的另一种说法。

11、spring的自动装配方式有哪些?
@Autowired的属性有1,no;2,default;3,byName;4,constructor;5,byType
@Qualifier、@Resource

12、spring中Bean的作用域?
singleton和prototype、request(对于每次HTTP请求,使用request定义的Bean都将产生一个新实例,即每次HTTP请求将会产生不同的Bean实例。只有在Web应用中使用Spring时,该作用域才有效)、session(对于每次HTTP Session,使用session定义的Bean豆浆产生一个新实例)、globalsession(每个全局的HTTP Session,使用session定义的Bean都将产生一个新实例。典型情况下,仅在使用portlet context的时候有效)

13、线程池
并发包中Executors提供了实现Executor接口用于创建线程池。
线程池显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力。
一个线程池包括以下四个基本组成部分:线程池管理器、工作线程、任务接口、任务队列
常见线程池:newSingleThreadExecutor、newFixedThreadExecutor(n)、newCacheThreadExecutor(推荐使用,可缓存线程池,当线程池大小超过了处理任务所需的线程,那么就会回收部分空闲(一般是60秒无执行)的线程,当有任务来时,又智能的添加新线程来执行。)、newScheduleThreadExecutor

14、JDK和JRE的区别
JDK(Java Development Kit)是针对Java开发员的产品,是整个Java的核心,包括了Java运行环境JRE、Java工具和Java基础类库。Java Runtime Environment(JRE)是运行JAVA程序所必须的环境的集合,包含JVM标准实现及Java核心类库。

15、==与equeals的区别
== 比较的是变量(栈)内存中存放的对象的(堆)内存地址,用来判断两个对象的地址是否相同,即是否是指相同一个对象。比较的是真正意义上的指针操作。

equals用来比较的是两个对象的内容是否相等,由于所有的类都是继承自java.lang.Object类的,所以适用于所有对象,如果没有对该方法进行覆盖的话,调用的仍然是Object类中的方法,而Object中的equals方法返回的却是==的判断。

16、hashCode()和equals的作用?
hashCode()方法和equal()方法的作用其实一样,都是用来对比两个对象是否相等一致,但hashCode()并不是完全可靠,有时候不同的对象他们生成的hashcode也会一样。
equal()相等的两个对象他们的hashCode()肯定相等;hashCode()相等的两个对象他们的equal()不一定相等。

17、final的作用?
final关键字可以用来修饰类、方法和变量。
当用final修饰一个类时,表明这个类不能被继承。
final修饰的方法表示此方法已经是“最后的、最终的”含义,亦即此方法不能被重写。
final成员变量表示常量,只能被赋值一次,赋值后值不再改变。

18、Math.round(-1.5)等于多少?
-1

19、String,StringBuilder,StringBuffer三者的区别
String为字符串常量,而StringBuilder和StringBuffer均为字符串变量;
StringBuilder是线程不安全的,而StringBuffer是线程安全的

20、String str = “i”;
String s2 = new String(“i”);
System.out.println(str == s2);
输出的结果:false

21、如何将字符串反转?
StringBuilder sb = new StringBuilder();
sb.append(“abcdefg”);
sb.reverse();
这样就可以反转字符串了。

22、String的常用方法有哪些?
length()、charAt(int index)、substring(int beginIndex)、compareTo(String anotherString)、equals(Object anotherObject)、concat(String str)、indexOf(int ch/String str)、lastIndexOf(int ch/String str, int fromIndex)、replace(char oldChar, char newChar)、split(String str)

23、抽象类和普通类及接口的区别?
普通类可以去实例化调用,抽象类不能被实例化。抽象类可以有抽象方法,子类继承抽象类必须实现抽象类的抽象方法。

接口不能包含变量,抽象类可以有具体的方法 和属性。
接口的方法必须实现,
类可以实现多个接口,但只能继承一个类。

24、IO流分为几种?
分为两种,一种是字节流,另一种是字符流,分别由四个抽象类来表示(每种流包括输入和输出两种所以一共四个):InputStream,OutputStream,Reader,Writer。

25、BIO、NIO、AIO有什么区别?

BIO:一个socket连接一个处理线程(这个线程负责这个Socket连接的一系列数据传输操作)。阻塞的原因在于:操作系统允许的线程数量是有限的,多个socket申请与服务端建立连接时,服务端不能提供相应数量的处理线程,没有分配到处理线程的连接就会阻塞等待或被拒绝。

NIO: 是对BIO的改进,基于Reactor模型。我们知道,一个socket连接只有在特定时候才会发生数据传输IO操作,大部分时间这个“数据通道”是空闲的,但还是占用着线程。NIO作出的改进就是“一个请求一个线程”,在连接到服务端的众多socket中,只有需要进行IO操作的才能获取服务端的处理线程进行IO。这样就不会因为线程不够用而限制了socket的接入。客户端的socket连接到服务端时,就会在事件分离器注册一个 IO请求事件 和 IO 事件处理器。在该连接发生IO请求时,IO事件处理器就会启动一个线程来处理这个IO请求,不断尝试获取系统的IO的使用权限,一旦成功(即:可以进行IO),则通知这个socket进行IO数据传输。

AIO:对NIO的改进(所以AIO又叫NIO.2),它是基于Proactor模型的。每个socket连接在事件分离器注册 IO完成事件 和 IO完成事件处理器。程序需要进行IO时,向分离器发出IO请求并把所用的Buffer区域告知分离器,分离器通知操作系统进行IO操作,操作系统自己不断尝试获取IO权限并进行IO操作(数据保存在Buffer区),操作完成后通知分离器;分离器检测到 IO完成事件,则激活 IO完成事件处理器,处理器会通知程序说“IO已完成”,程序知道后就直接从Buffer区进行数据的读写。

26、java容器有哪些?
List、set、Map、queue

27、List、Set、Map之间的区别是什么?
List 是可重复集合,Set 是不可重复集合,这两个接口都实现了 Collection 父接口。
Map 是一种把键对象和值对象进行映射的集合,它的每一个元素都包含了一对键对象和值对象,Map 中存储的数据是没有顺序的, 其 key 是不能重复的,它的值是可以有重复的。

List 的实现类有 ArrayList,Vector 和 LinkedList
ArrayList 和 Vector 内部是线性动态数组结构,在查询效率上会高很多
LinkedList:是双向链表的数据结构存储数据,在做查询时会按照序号索引数据进行前向或后向遍历,查询效率偏低,但插入数据时只需要记录本项的前后项即可,所以插入速度较快。

Set 的实现类有 HashSet 和 TreeSet
HashSet:内部是由哈希表(实际上是一个 HashMap 实例)支持的。它不保证 set 元素的迭代顺序。
TreeSet:TreeSet 使用元素的自然顺序对元素进行排序,或者根据创建 set 时提供的 Comparator 进行排序。

Map 接口实现类:Hashtable,HashMap,TreeMap,LinkedHashMap
Hashtable:内部存储的键值对是无序的是按照哈希算法进行排序,与 HashMap 最大的区别就是线程安全。键或者值不能为 null,为 null 就会抛出空指针异常。
TreeMap:基于红黑树 (red-black tree) 数据结构实现,按 key 排序,默认的排序方式是升序。
LinkedHashMap:有序的 Map 集合实现类,相当于一个栈,先 put 进去的最后出来,先进后出。

28、hashMap、TreeMap、LinkedHashMap的使用场景?
TreeMap是基于红黑树的实现的排序Map,对于增删改查以及统计的时间复杂度都控制在O(logn)的级别
HashMap和LikedHashMap 这些 hash表的时间复杂度O(1)

需要基于排序的统计功能使用TreeMap
需要快速增删改查的存储功能hashMap
需要快速增删改查而且需要保证遍历和插入顺序一致的存储功能LinkedHashMap

29、HashMap的实现原理?
HashMap存储的是key-value的键值对,允许key为null,也允许value为null。HashMap内部为数组+链表的结构,会根据key的hashCode值来确定数组的索引(确认放在哪个桶里),如果遇到索引相同的key,桶的大小是2,如果一个key的hashCode是7,一个key的hashCode是3,那么他们就会被分到一个桶中(hash冲突),如果发生hash冲突,HashMap会将同一个桶中的数据以链表的形式存储,但是如果发生hash冲突的概率比较高,就会导致同一个桶中的链表长度过长,遍历效率降低,所以在JDK1.8中如果链表长度到达阀值(默认是8),就会将链表转换成红黑二叉树。

负载因子是0.75,每次都是扩容为原来的2倍。
put方法:
1.table[]是否为空
2.判断table[i]处是否插入过值
3.判断链表长度是否大于8,如果大于就转换为红黑二叉树,并插入树中
4.判断key是否和原有key相同,如果相同就覆盖原有key的value,并返回原有value
5.如果key不相同,就插入一个key,记录结构变化一次

get方法实现:
1.判断表或key是否是null,如果是直接返回null
2.判断索引处第一个key与传入key是否相等,如果相等直接返回
3.如果不相等,判断链表是否是红黑二叉树,如果是,直接从树中取值
4.如果不是树,就遍历链表查找

30、HashSet的实现原理?
HashSet是基于HashMap实现的。

31、Queue中remove()和poll()的区别?
如果队列为空,poll()返回null,remove()则抛出NoSuchElementException异常

32、哪些集合类是线程安全的?
Vector、HashTable、ConcurrentHashMap、Stack、ArrayBlockingQueue、CopyOnWriteArrayList

33、什么是Iterator?
迭代器就是遍历集合取出元素的方式,迭代器可以取出并操作集合中的元素。
Iterator模式是用于遍历集合类的标准访问方法。它可以把访问逻辑从不同类型的集合类中抽象出来,从而避免向客户端暴露集合的内部结构。

使用next()获得序列中的下一个元素;使用hasNext()检查序列中是否还有元素;使用remove()将迭代器新返回的元素删除。

34、怎么确保一个集合不能被修改?
使用Collections工具类的方法UnmodifiableSet、UnmodifiableList、UnmodifiableMap

35、并行和并发的区别?
并发的关键是你有处理多个任务的能力,不一定要同时
并行的关键是你有同时处理多个任务的能力

36、线程和进程的区别?
进程是资源分配的最小单位一个应用程序就是一个进程,线程是程序执行的最小单位。
进程有自己的独立地址空间,每启动一个进程,系统就会为它分配地址空间,建立数据表来维护代码段、堆栈段和数据段,这种操作非常昂贵。而线程是共享进程中的数据的,使用相同的地址空间,因此CPU切换一个线程的花费远比进程要小很多,同时创建一个线程的开销也比进程要小很多。
线程之间的通信更方便,进程程序更健壮。

37、守护线程是什么?
在Java中有两类线程:User Thread(用户线程)、Daemon Thread(守护线程)
存在任何一个非守护线程没有结束,守护线程就全部工作;只有当最后一个非守护线程结束时,守护线程随着JVM一同结束工作。

38、创建线程有哪几种方式?

  1. 继承 Thread 类,然后调用 start 方法。
  2. 实现 Runnable 接口的 run 方法, 然后再用 Thread 类包裹后,调用 start 方法
  3. 实现 Callable 接口的 call 方法,用 FutureTask 类包裹 Callable 对象。然后再用 Thread 类包裹 FutureTask 类,并调用 start 方法。call() 方法可以有返回值。

39、线程有哪些状态?
线程的生命周期大体可分为5种状态:

  1. 新建(NEW):新创建了一个线程对象。

  2. 可运行(RUNNABLE):线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取cpu 的使用权 。

  3. 运行(RUNNING):可运行状态(runnable)的线程获得了cpu 时间片(timeslice) ,执行程序代码。

  4. 阻塞(BLOCKED):阻塞状态是指线程因为某种原因放弃了cpu 使用权,也即让出了cpu timeslice,暂时停止运行。直到线程进入可运行(runnable)状态,才有机会再次获得cpu timeslice 转到运行(running)状态。阻塞的情况分三种:
    (一). 等待阻塞:运行(running)的线程执行o.wait()方法,JVM会把该线程放入等待队列(waitting queue)中。
    (二). 同步阻塞:运行(running)的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池(lock pool)中。
    (三). 其他阻塞:运行(running)的线程执行Thread.sleep(long ms)或t.join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入可运行(runnable)状态。

  5. 死亡(DEAD):线程run()、main() 方法执行结束,或者因异常退出了run()方法,则该线程结束生命周期。死亡的线程不可再次复生。

40、sleep和wait的区别?
sleep是Thread线程类的方法,而wait是Object顶级类的方法。
sleep方法没有释放锁,而wait方法释放了锁
wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用
sleep必须捕获异常,而wait,notify和notifyAll不需要捕获异常

41、线程的run()和start()有什么区别?
调用run()只是调用这个方法;调用start()启动了一个线程

42、线程池中submit()和execute()方法有什么区别?
submit有返回值,而execute没有
submit方便Exception处理

43、如何保证线程安全性?
线程安全在三个方面体现:1.原子性:提供互斥访问,同一时刻只能有一个线程对数据进行操作,(atomic,synchronized);

2.可见性:一个线程对主内存的修改可以及时地被其他线程看到,(synchronized,volatile);

3.有序性:一个线程观察其他线程中的指令执行顺序,由于指令重排序,该观察结果一般杂乱无序,(happens-before原则)。

44、什么是死锁,怎么预防?
程死锁是指由于两个或者多个线程互相持有对方所需要的资源,导致这些线程处于等待状态,无法前往执行。
死锁的产生是必须要满足一些特定条件的:
1.互斥条件:进程对于所分配到的资源具有排它性,即一个资源只能被一个进程占用,直到被该进程释放
2.请求和保持条件:一个进程因请求被占用资源而发生阻塞时,对已获得的资源保持不放。
3.不剥夺条件:任何一个资源在没被该进程释放之前,任何其他进程都无法对他剥夺占用
4.循环等待条件:当发生死锁时,所等待的进程必定会形成一个环路(类似于死循环),造成永久阻塞。

避免死锁的技术:加锁顺序、加锁时限、死锁检测

45、ThreadLocal原理及使用场景?
它是线程的局部变量,这些变量只能在这个线程内被读写,在其他线程内是无法访问的。 ThreadLocal 定义的通常是与线程关联的私有静态字段。
当我们只想在本身的线程内使用的变量,可以用 ThreadLocal 来实现,并且这些变量是和线程的生命周期密切相关的,线程结束,变量也就销毁了。数据库连接、Session管理等可以用到 ThreadLocal
ThreadLocal 的使用非常简单,最核心的操作就是四个:创建、创建并赋初始值、赋值、取值。initialValue()、set()、get()、remove()

46、synchronized和reentrantLock的区别?
synchronized是在JVM层面上实现的,不但可以通过一些监控工具监控synchronized的锁定,而且在代码执行时出现异常,JVM会自动释放锁定,但是使用Lock则不行,lock是通过代码实现的,要保证锁定一定会被释放,就必须将unLock()放到finally{}中。

47、atomic的原理?
通过CAS乐观锁保证原子性,通过自旋保证当次修改的最终修改成功,通过降低锁粒度(多段锁)增加并发性能。

48、什么是反射?
运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;并且能改变它的属性。

49、序列化是什么,什么情况下需要使用?
序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化。可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间。
网络传输或将对象写入到文件中。

50、动态代理是什么?有哪些应用?怎么实现?
动态代理,利用Java的反射技术(Java Reflection),在运行时创建一个实现某些给定接口的新类及其实例。
应用场景:适配器(Adapter)或修饰器(Decorator)、面向切面编程
1、调用Proxy.newProxyInstance();这个方法有三个参数,
类加载器(Class Loader);需要实现的接口数组;InvocationHandler接口。所有动态代理类的方法调用,都会交由InvocationHandler接口实现类里的invoke()方法去处理。这是动态代理的关键所在。

2、cglib实现
类要实现MethodInterceptor接口,包含cglib的jar包

51、深复制(深克隆)与浅复制(浅克隆)
浅复制:被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅复制仅仅复制所拷贝的对象,而不复制它所引用的对象。
深复制:被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。
必须要实现Cloneable 接口。

52、Jsp和servlet的区别?
jsp经编译后就变成了Servlet;jsp更擅长表现于页面显示,servlet更擅长于逻辑控制;Servlet中没有内置对象,Jsp中的内置对象都是必须通过HttpServletRequest对象,HttpServletResponse对象以及HttpServlet对象得到

53、Jsp的内置对象有哪些?作用域有哪些?
1.request 用户端请求
2.response 网页传回用户端回应
3.pageContext 网页的属性在这里管理
3、session 与请求有关会话期
4、application servlet正在执行的内容
5、out 用来传送回应的输出
6、config servlet的架构部件
7、page JSP网页本身
8、exception 针对错误网页,未捕捉的列外
JSP四大作用域分别为:page, request ,session, application

54、session和cookie的区别?
1、cookie数据存放在客户的浏览器上,session数据放在服务器上。
2、cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗
考虑到安全应当使用session。
3、session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能
考虑到减轻服务器性能方面,应当使用COOKIE。
4、单个cookie保存的数据不能超过4K

55、怎么避免sql注入?什么是XSS攻击,怎么避免?什么是CSRF攻击,怎么避免?
使用PreparedStatement语句;
XSS(Cross Site Scripting),即跨站脚本攻击,是一种常见于web应用程序中的计算机安全漏洞.XSS通过在用户端注入恶意的可运行脚本,若服务器端对用户输入不进行处理,直接将用户输入输出到浏览器,然后浏览器将会执行用户注入的脚本。
对用户输入进行过滤;

CSRF(Cross-site request forgery)跨站请求伪造:攻击者诱导受害者进入第三方网站,在第三方网站中,向被攻击网站发送跨站请求。利用受害者在被攻击网站已经获取的注册凭证,绕过后台的用户验证,达到冒充用户对被攻击的网站执行某项操作的目的。
目前防御 CSRF 攻击主要有三种策略:验证 HTTP Referer 字段;在请求地址中添加 token 并验证;在 HTTP 头中自定义属性并验证。

56、throw和throws的区别?
throws是用来声明一个方法可能抛出的所有异常信息,throws是将异常声明但是不处理,而是将异常往上传,谁调用我就交给谁处理。而throw则是指抛出的一个具体的异常类型。

57、final、finally、finalize的区别?
final可以用来修饰类,方法和变量
当用final修饰类的时,表明该类不能被其他类所继承。
final方法意味着“最后的、最终的”含义,即此方法不能被重写。
final成员变量表示常量,只能被赋值一次,赋值后其值不再改变。
finally作为异常处理的一部分,它只能用在try/catch语句中,并且附带一个语句块,表示这段语句最终一定会被执行(不管有没有抛出异常),经常被用在需要释放资源的情况下。
finalize()是在java.lang.Object里定义的,也就是说每一个对象都有这么个方法。这个方法在gc启动,该对象被回收的时候被调用。

58、常见的异常类有哪些?
IllegalArgumentException、IllegalStateException 、UnsupportedOperationException、NumberFormatException、IndexOutOfBoundsExecption、NoSuchMethodException、IOException、SQLException、NumberFormatException、ClassCastException、ArrayIndexOutOfBoundsException、NullPointerException

59、Tcp和udp的区别?
1、TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接
2、TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付
3、TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;UDP是面向报文的UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如IP电话,实时视频会议等)
4、每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信
5、TCP首部开销20字节;UDP的首部开销小,只有8个字节
6、TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道

60、简述tcp的三次握手和四次挥手的流程,为什么断开连接要 4 次,如果握手只有两次,会出现什么?
第一次握手(SYN=1, seq=x):

客户端发送一个 TCP 的 SYN 标志位置1的包,指明客户端打算连接的服务器的端口,以及初始序号 X,保存在包头的序列号(SequenceNumber)字段里。
发送完毕后,客户端进入 SYN_SEND 状态。

第二次握手(SYN=1, ACK=1,seq=y, ACKnum=x+1):

服务器发回确认包(ACK)应答。即 SYN 标志位和 ACK 标志位均为1。服务器端选择自己 ISN 序列号,放到 Seq 域里,同时将确认序号(AcknowledgementNumber)设置为客户的 ISN 加1,即X+1。 发送完毕后,服务器端进入 SYN_RCVD 状态。
第三次握手(ACK=1,ACKnum=y+1)

客户端再次发送确认包(ACK),SYN 标志位为0,ACK 标志位为1,并且把服务器发来 ACK 的序号字段+1,放在确定字段中发送给对方,并且在数据段放写ISN的+1
发送完毕后,客户端进入 ESTABLISHED 状态,当服务器端接收到这个包时,也进入 ESTABLISHED 状态,TCP 握手结束。

握手过程中传送的包里不包含数据,三次握手完毕后,客户端与服务器才正式开始传送数据。理想状态下,TCP连接一旦建立,在通信双方中的任何一方主动关闭连接之前,TCP 连接都将被一直保持下去。

四次挥手指断开连接的过程
第一次挥手(FIN=1,seq=x)

假设客户端想要关闭连接,客户端发送一个 FIN 标志位置为1的包,表示自己已经没有数据可以发送了,但是仍然可以接受数据。
发送完毕后,客户端进入 FIN_WAIT_1 状态。

第二次挥手(ACK=1,ACKnum=x+1)

服务器端确认客户端的 FIN 包,发送一个确认包,表明自己接受到了客户端关闭连接的请求,但还没有准备好关闭连接。
发送完毕后,服务器端进入 CLOSE_WAIT 状态,客户端接收到这个确认包之后,进入 FIN_WAIT_2 状态,等待服务器端关闭连接。

第三次挥手(FIN=1,seq=y)

服务器端准备好关闭连接时,向客户端发送结束连接请求,FIN 置为1。
发送完毕后,服务器端进入 LAST_ACK 状态,等待来自客户端的最后一个ACK。

第四次挥手(ACK=1,ACKnum=y+1)

客户端接收到来自服务器端的关闭请求,发送一个确认包,并进入 TIME_WAIT状态,等待可能出现的要求重传的 ACK 包。
服务器端接收到这个确认包之后,关闭连接,进入 CLOSED 状态。

客户端等待了某个固定时间(两个最大段生命周期,2MSL,2 MaximumSegment Lifetime)之后,没有收到服务器端的 ACK ,认为服务器端已经正常关闭连接,于是自己也关闭连接,进入 CLOSED 状态。
两次后会重传直到超时。如果多了会有大量半链接阻塞队列。

如果只有两次握手,客户端到服务器的连接是成功的,但服务器到客户端的连接是不确认的。

61、osi的七层模型有哪些?
第7层应用层—直接对应用程序提供服务,应用程序可以变化,但要包括电子消息传输
第6层表示层—格式化数据,以便为应用程序提供通用接口。这可以包括加密服务
第5层会话层—在两个节点之间建立端连接。此服务包括建立连接是以全双工还是以半双工的方式进行设置,尽管可以在层4中处理双工方式
第4层传输层—常规数据递送-面向连接或无连接。包括全双工或半双工、流控制和错误恢复服务
第3层网络层—本层通过寻址来建立两个节点之间的连接,它包括通过互连网络来路由和中继数据
第2层数据链路层—在此层将数据分帧,并处理流控制。本层指定拓扑结构并提供硬件寻址
第1层物理层—原始比特流的传输电子信号传输和硬件接口数据发送时,从第七层传到第一层,接受方则相反。

62、get和post的区别?
get,参数url可见;post,url参数不可见
get,通过拼接url进行传递参数;post,通过body体传输参数
get请求是可以缓存的post请求不可以缓存
get请求页面后退时,不产生影响;post请求页面后退时,会重新提交请求
get一般传输数据大小不超过2k-4k(根据浏览器不同,限制不一样,但相差不大)
post请求传输数据的大小根据php.ini 配置文件设定,也可以无限大。

63、如何实现跨域?
浏览器对于javascript的同源策略的限制,例如a.cn下面的js不能调用b.cn中的js,对象或数据(因为a.cn和b.cn是不同域),所以跨域就出现了。
服务器一般需要增加如下响应头的一种或几种:Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
Access-Control-Max-Age: 86400

65、常用的设计模式?
单例模式、工厂模式、观察者模式、适配器(Adapter)模式、代理模式、装饰模式

66、简单工厂和抽象工厂的区别?
简单工厂:工厂类(SimpleFactory)拥有一个工厂方法(create),接受了一个参数,通过不同的参数实例化不同的产品类。
工厂方法:工厂方法是针对每一种产品提供一个工厂类。通过不同的工厂实例来创建不同的产品实例。
抽象工厂:抽象工厂是应对产品族概念的。

67、什么是aop、Ioc?
依赖注入(Dependecy Injection)和控制反转(Inversion of Control)是同一个概念,具体的讲:创建被调用者的工作不再由调用者来完成,而是由Spring容器完成,依赖关系被反转了,称为控制反转 。
AOP(Aspect Oriented Programming)面向方面编程, 将通用需求功能从不相关类之中分离出来;同时,能够使得很多类共享一个行为,一旦行为发生变化,不必修改很多类,只要修改这个行为就可以。

68、spring有哪些主要模块?
core、beans、context、 expression language、web、webmvc、aop、orm、dao

69、Spring中的Bean是线程安全的吗?
Spring容器中的Bean本身不具备线程安全的特性,但是具体还是要结合具体scope的Bean去研究。
prototype:对于原型Bean,每次创建一个新对象,也就是线程之间并不存在Bean共享,自然是不会有线程安全的问题。

singleton:对于单例Bean,所有线程都共享一个单例实例Bean,因此是存在资源的竞争。

70、spring运行流程
用户发起请求到前端控制器(DispatcherServlet),该控制器会过滤出哪些请求可以访问Servlet、哪些不能访问。就是url-pattern的作用,并且会加载springmvc.xml配置文件。
前端控制器会找到处理器映射器(HandlerMapping),通过HandlerMapping完成url到controller映射的组件,简单来说,就是将在springmvc.xml中配置的或者注解的url与对应的处理类找到并进行存储,用map<url,handler>这样的方式来存储。
HandlerMapping有了映射关系,并且找到url对应的处理器,HandlerMapping就会将其处理器(Handler)返回,在返回前,会加上很多拦截器。
DispatcherServlet拿到Handler后,找到HandlerAdapter(处理器适配器),通过它来访问处理器,并执行处理器。
执行处理器
处理器会返回一个ModelAndView对象给HandlerAdapter
通过HandlerAdapter将ModelAndView对象返回给前端控制器(DispatcherServlet)
前端控制器请求视图解析器(ViewResolver)去进行视图解析,根据逻辑视图名解析成真正的视图(jsp),其实就是将ModelAndView对象中存放视图的名称进行查找,找到对应的页面形成视图对象
返回视图对象到前端控制器。
视图渲染,就是将ModelAndView对象中的数据放到request域中,用来让页面加载数据的。
通过第8步,通过名称找到了对应的页面,通过第10步,request域中有了所需要的数据,那么就能够进行视图渲染了。最后将其返回即可。
在这里插入图片描述

71、springmvc有哪些组件?

  1. 前端控制器组件(DispatcherServlet)
    2. 处理器组件(Controller)
    3. 处理器映射器组件(HandlerMapping)
    4. 处理器适配器组件(HandlerAdapter)
    5. 拦截器组件(HandlerInterceptor)
    6. 视图解析器组件(ViewResolver)
    7. 视图组件(View)
    8. 数据转换组件(DataBinder)
    9. 消息转换器组件(HttpMessageConverter)

72、什么是springboot?为什么要用?
SpringBoot是一个框架,一种全新的编程规范,他的产生简化了框架的使用,所谓简化是指简化了Spring众多框架中所需的大量且繁琐的配置文件,所以 SpringBoot是一个服务于框架的框架,服务范围是简化配置文件。

  1. 配置简单了
      2. springboot内嵌了servlet容器,降低了对环境的要求,机器有java运行环境,可以将项目打包成jar包,通过java命令 java -jar ****.jar 来执行。
    3. 快速整合第三方框架,无需配置文件
    4. 代码少了、配置文件少了、不需要对第三方框架烦恼了、项目精简了,对整个团队的开发及维护来说,更大的节约了成本。

73、springboot核心配置文件是什么?
bootstrap和application(.yml或.properties)
bootstrap由父ApplicationContext加载,优先于application;
bootstrap主要用于从额外的资源来加载配置信息,还可以在本地外部配置文件中解密属性。不能被本地相同配置覆盖。

74、springboot哪些方式实现热部署
1.使用springloaded配置pom.xml文件,使用mvn spring-boot:run启动

2.使用springloaded本地加载启动,配置jvm参数

-javaagent:<jar包地址> -noverify

3.使用devtools工具包,操作简单,但是每次需要重新部署

75、jpa和hibernate的区别?
JPA本身是一种规范,它的本质是一种ORM规范,只是提供了一些相关的接口,但是接口并不能直接使用,JPA底层需要某种JPA实现,JPA现在就是Hibernate功能的一个子集。
Hibernate属于遵循JPA规范的一种实现,但是JPA是Hibernate遵循的规范之一,Hibernate还有其他实现的规范。

76、什么是springcloud?
Spring Cloud是一个微服务框架,相比Dubbo等RPC框架, Spring Cloud提供的全套的分布式系统解决方案。
Spring Cloud为微服务架构开发涉及的配置管理,服务治理,熔断机制,智能路由,微代理,控制总线,一次性token,全局一致性锁,leader选举,分布式session,集群状态管理等操作提供了一种简单的开发方式。

77、springcloud断路器的作用?
在分布式架构中,断路器模式的作用也是类似的,当某个服务单元发生故障(类似用电器发生短路)之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个错误响应,而不是长时间的等待。这样就不会使得线程因调用故障服务被长时间占用不释放,避免了故障在分布式系统中的蔓延。

78、springcloud核心组件有哪些?
服务发现——Netflix Eureka
客服端负载均衡——Netflix Ribbon
断路器——Netflix Hystrix
服务网关——Netflix Zuul
分布式配置——Spring Cloud Config
服务调用 Feign

79、Mybatis中#{}和${}的区别?
#{}将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号,能够很大程度防止sql注入。
$将传入的数据直接显示生成在sql中,无法防止Sql注入,一般用于传入数据库对象,例如传入表名。

80、Mybatis有几种分页方式?
1、查询出全部数据,然后再list中截取需要的部分
2、sql分页
3、PageHelper分页插件

81、mybatis逻辑分页和物理分页的区别?
逻辑分页 内存开销比较大,在数据量比较小的情况下效率比物理分页高;在数据量很大的情况下,内存开销过大,容易内存溢出;
物理分页 内存开销比较小,在数据量比较小的情况下效率比逻辑分页还是低,在数据量很大的情况下,建议使用物理分页
逻辑分页是将查询的所有结果放置在内存中,每次都从内存获取。
物理分页每次只查询对应条目数量的数据,从而实现了真正意义上的分页。

82、mybatis是否支持延迟加载,实现原理是什么?
通常会进行多表联合查询,但是有的时候并不会立即用到所有的联合查询结果,此时需要一种机制,当需要的时候再查询,这种“按需查询”的机制,就可以使用延迟加载来实现。
lazyLoadingEnabled设置为true
aggressiveLazyLoading设置为false

83、mybatis一级缓存和二级缓存?
合理使用缓存是优化中最常见的,将从数据库中查询出来的数据放入缓存中,下次使用时不必从数据库查询,而是直接从缓存中读取,避免频繁操作数据库,减轻数据库的压力,同时提高系统性能。
一级缓存是SqlSession级别的缓存。在操作数据库时需要构造sqlSession对象,在对象中有一个数据结构用于存储缓存数据。不同的sqlSession之间的缓存数据区域是互相不影响的。也就是他只能作用在同一个sqlSession中,不同的sqlSession中的缓存是互相不能读取的。
二级缓存是mapper级别的缓存,多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。二级缓存的作用范围更大。

84、mybatis于hibernate的区别?
hibernate开发中,sql语句已经被封装,直接可以使用,加快系统开发;
Mybatis 属于半自动化,sql需要手工完成,稍微繁琐;
Hibernate 自动生成sql,有些语句较为繁琐,会多消耗一些性能;
Mybatis 手动编写sql,可以避免不需要的查询,提高系统性能;
Hibernate 是完整的对象-关系映射的框架,开发工程中,无需过多关注底层实现,只要去管理对象即可;
Mybatis 需要自行管理 映射关系;

85、Mybatis都有哪些Executor执行器?它们之间的区别是什么?
Mybatis有三种基本的Executor执行器,SimpleExecutor、ReuseExecutor、BatchExecutor。

SimpleExecutor:每执行一次update或select,就开启一个Statement对象,用完立刻关闭Statement对象。

ReuseExecutor:执行update或select,以sql作为key查找Statement对象,存在就使用,不存在就创建,用完后,不关闭Statement对象,而是放置于Map<String, Statement>内,供下一次使用。简言之,就是重复使用Statement对象。

BatchExecutor:执行update(没有select,JDBC批处理不支持select),将所有sql都添加到批处理中(addBatch()),等待统一执行(executeBatch()),它缓存了多个Statement对象,每个Statement对象都是addBatch()完毕后,等待逐一执行executeBatch()批处理。与JDBC批处理相同。
作用范围:Executor的这些特点,都严格限制在SqlSession生命周期范围内。

86、分页插件的原理是什么?以及如何编写一个插件?
分页插件的基本原理是使用Mybatis提供的插件接口,实现自定义插件,在插件的拦截方法内拦截待执行的sql,然后重写sql,根据dialect方言,添加对应的物理分页语句和物理分页参数。
举例:select * from student,拦截sql后重写为:select t.* from (select * from student)t limit 0,10
Mybatis仅可以编写针对ParameterHandler、ResultSetHandler、StatementHandler、Executor这4种接口的插件,Mybatis使用JDK的动态代理,为需要拦截的接口生成代理对象以实现接口方法拦截功能,每当执行这4种接口对象的方法时,就会进入拦截方法,具体就是InvocationHandler的invoke()方法,当然,只会拦截那些你指定需要拦截的方法。
实现Mybatis的Interceptor接口并复写intercept()方法,然后在给插件编写注解,指定要拦截哪一个接口的哪些方法即可,记住,别忘了在配置文件中配置你编写的插件。

87、rabbitmq使用场景有哪些?
发送手机验证码,邮件;.应用解耦;流量削峰;日志处理;消息通讯

88、rabbitmq的重要组件?
消费者、生产者、队列、交换器

89、rabbitmq中vhost作用?
每个virtual host本质上都是一个RabbitMQ Server,拥有它自己的queue,exchagne,和bings rule等等。这保证了你可以在多个不同的application中使用RabbitMQ。

90、如何确保rabbitMQ消息的可靠性?
publisher confirms(发布方确认);
message持久化;
acknowledgement(consumer确认)。

91、RabbitMQ 如何保证消息不丢失?
消息持久化:要想做到消息持久化,必须满足以下三个条件,缺一不可(Exchange 设置持久化、Queue 设置持久化、Message持久化发送);
要在producer引入事务机制或者Confirm机制来确保消息已经正确的发送至broker端
ACK确认机制;
设置集群镜像模式;
消息补偿机制。

92、rabbitmq怎么实现延迟消息队列?
消息的TTL就是消息的存活时间(Time To Live),RabbitMQ可以对队列和消息分别设置TTL。对队列设置就是队列没有消费者连着的保留时间,也可以对每一个单独的消息做单独的设置。超过了这个时间,我们认为这个消息就死了,称之为死信。如果队列设置了,消息也设置了,那么会取小的。单靠死信还不能实现延迟任务,还要靠Dead Letter Exchange。
一个消息在满足如下条件下,会进死信路由,记住这里是路由而不是队列,一个路由可以对应很多队列。1、一个消息被Consumer拒收了,并且reject方法的参数里requeue是false。也就是说不会被再次放在队列里,被其他消费者使用。2、上面的消息的TTL到了,消息过期了;3、队列的长度限制满了。排在前面的消息会被丢弃或者扔到死信路由上。

实现延迟队列:延迟任务通过消息的TTL和Dead Letter Exchange来实现。我们需要建立2个队列,一个用于发送消息,一个用于消息过期后的转发目标队列。
第一步:给队列或者指定消息设置过期时间(TTL),过期后变成 死信
第二部:设置死信的转发规则(如果没有任何规则,则直接丢弃死信) ,从新消费

93、rabbitmq集群有什么用?
rabbitmq有3种模式,但集群模式是2种。
单一模式:即单机情况不做集群,就单独运行一个rabbitmq而已。
普通模式:默认模式,以两个节点(rabbit01、rabbit02)为例来进行说明。对于Queue来说,消息实体只存在于其中一个节点rabbit01(或者rabbit02),rabbit01和rabbit02两个节点仅有相同的元数据,即队列的结构。当消息进入rabbit01节点的Queue后,consumer从rabbit02节点消费时,RabbitMQ会临时在rabbit01、rabbit02间进行消息传输,把A中的消息实体取出并经过B发送给consumer。所以consumer应尽量连接每一个节点,从中取消息。即对于同一个逻辑队列,要在多个节点建立物理Queue。否则无论consumer连rabbit01或rabbit02,出口总在rabbit01,会产生瓶颈。当rabbit01节点故障后,rabbit02节点无法取到rabbit01节点中还未消费的消息实体。如果做了消息持久化,那么得等rabbit01节点恢复,然后才可被消费;如果没有持久化的话,就会产生消息丢失的现象。
镜像模式:把需要的队列做成镜像队列,存在与多个节点属于RabbitMQ的HA方案。该模式解决了普通模式中的问题,其实质和普通模式不同之处在于,消息实体会主动在镜像节点间同步,而不是在客户端取数据时临时拉取。该模式带来的副作用也很明显,除了降低系统性能外,如果镜像队列数量过多,加之大量的消息进入,集群内部的网络带宽将会被这种同步通讯大大消耗掉。所以在对可靠性要求较高的场合中适用。

允许消费者和生产者在Rabbit节点崩溃的情况下继续运行;
通过增加节点来扩展Rabbit处理更多的消息,承载更多的业务量;

94、rabbitmq 的消息是怎么发送的?
(1)客户端连接到消息队列服务器,打开一个channel。
(2)客户端声明一个exchange,并设置相关属性。
(3)客户端声明一个queue,并设置相关属性。
(4)客户端使用routing key,在exchange和queue之间建立好绑定关系。
(5)客户端投递消息到exchange。

95、rabbitmq 怎么保证消息的稳定性?
费者在消费完消息后发送一个回执给RabbitMQ,RabbitMQ收到消息回执(Message acknowledgment)后才将该消息从Queue中移除;如果RabbitMQ没有收到回执并检测到消费者的RabbitMQ连接断开,则RabbitMQ会将该消息发送给其他消费者(如果存在多个消费者)进行处理。

96、rabbitmq 持久化有什么缺点?
一、如果消息的自动确认为true,那么在消息被接收以后,RabbitMQ就会删除该消息,假如消费端此时宕机,那么消息就会丢失。因此需要将消息设置为手动确认。
二、设置手动确认会出现另一个问题,如果消息已被成功处理,但在消息确认过程中出现问题,那么在消费端重启后,消息会重新被消费。
三、发送端为了保证消息会成功投递,一般会设定重试。如果消息发送至RabbitMQ之后,在RabbitMQ回复已成功接收消息过程中出现异常,那么发送端会重新发送该消息,从而造成消息重复发送。
四、RabbitMQ的消息磁盘写入,如果出现问题,也会造成消息丢失。

97、rabbitmq 有几种广播类型?
fanout: 所有bind到此exchange的queue都可以接收消息(纯广播,绑定到RabbitMQ的接受者都能收到消息);
direct: 通过routingKey和exchange决定的那个唯一的queue可以接收消息;
topic:所有符合routingKey(此时可以是一个表达式)的routingKey所bind的queue可以接收消息;

98、rabbitmq 节点的类型有哪些?
内存节点、磁盘节点。顾名思义内存节点就是将所有数据放在内存,磁盘节点将数据放在磁盘

99、rabbitmq 集群搭建需要注意哪些问题?
每个节点Cookie的同步;主机之间 必须可以相互识别并可达,/etc/hosts文件配置必须准确

100、rabbitmq 每个节点是其他节点的完整拷贝吗?为什么?
不是,队列的完整信息只放在一个节点,其他节点存放的是该队列的指针

101、rabbitmq 集群中唯一一个磁盘节点崩溃了会发生什么情况?
如果唯一的磁盘节点崩溃,集群是可以保持运行的,但不能更改任何东西。

不能创建队列
不能创建交换器
不能创建绑定
不能添加用户
不能更改权限
不能添加和删除集群几点

102、rabbitmq 对集群节点停止顺序有要求吗?
启动顺序:磁盘节点 => 内存节点
关闭顺序:内存节点 => 磁盘节点

103、ZooKeeper是什么?
ZooKeeper是一个经典的分布式数据一致性解决方案,致力于为分布式应用提供一个高性能、高可用,且具有严格顺序访问控制能力的分布式协调服务。
分布式应用程序可以基于ZooKeeper实现数据发布与订阅、负载均衡、命名服务、分布式协调与通知、集群管理、Leader选举、分布式锁、分布式队列等功能。

104、zookeeper有哪些功能?
.配置中心
2.命名服务
3.Master选举
4.分布式锁
5.服务注册与推送

105、zookeeper有几种部署模式?
分为三种模式:单机模式、集群模式和伪集群模式。

106、zookeeper怎样保证主从节点的状态同步?
Zookeeper的核心是原子广播机制,这个机制保证了各个server之间的同步。实现这个机制的协议叫做Zab协议。Zab协议有两种模式,它们分别是恢复模式和广播模式。
(1) 恢复模式
当服务启动或者在领导者崩溃后,Zab就进入了恢复模式,当领导者被选举出来,且大多数server完成了和leader的状态同步以后,恢复模式就结束了。状态同步保证了leader和server具有相同的系统状态。
(2) 广播模式
一旦Leader已经和多数的Follower进行了状态同步后,他就可以开始广播消息了,即进入广播状态。这时候当一个Server加入ZooKeeper服务中,它会在恢复模式下启动,发现Leader,并和Leader进行状态同步。待到同步结束,它也参与消息广播。ZooKeeper服务一直维持在Broadcast状态,直到Leader崩溃了或者Leader失去了大部分的Followers支持。
数据一致性是靠Paxos算法保证的,Paxos可以说是分布式一致性算法的鼻祖,是ZooKeeper的基础

107、集群中为什么要有主节点?
在分布式环境中,有些业务逻辑只需要集群中的某一台机器进行执行,其他的机器可以共享这个结果,这样可以大大减少重复计算,提高性能,所以就需要主节点。

108、集群中有 3 台服务器,其中一个节点宕机,这个时候 zookeeper 还可以使用吗?
可以继续使用,单数服务器只要没超过一半的服务器宕机就可以继续使用。

109、说一下 zookeeper 的通知机制?
客户端端会对某个 znode 建立一个 watcher 事件,当该 znode 发生变化时,这些客户端会收到 zookeeper 的通知,然后客户端可以根据 znode 变化来做出业务上的改变。

110、数据库的三范式?
第一范式:当关系模式R的所有属性都不能在分解为更基本的数据单位时,称R是满足第一范式的
第二范式:如果关系模式R满足第一范式,并且R得所有非主属性都完全依赖于R的每一个候选关键属性,称R满足第二范式
第三范式:设R是一个满足第一范式条件的关系模式,X是R的任意属性集,如果X非传递依赖于R的任意一个候选关键字,称R满足第三范式

111、一张表里面有ID自增主键,当insert了17条记录之后,删除了第15,16,17条记录,再把mysql重启,再insert一条记录,这条记录的ID是18还是15 ?
一般情况下,我们创建的表的类型是InnoDB,如果新增一条记录(不重启mysql的情况下),这条记录的id是18;但是如果重启(文中提到的)MySQL的话,这条记录的ID是15。因为InnoDB表只把自增主键的最大ID记录到内存中,所以重启数据库或者对表OPTIMIZE操作,都会使最大ID丢失。

112、mysql如何获取当前数据库版本?
select version();

113、ACID是什么?
1.Atomicity 原子性
2.Consistency 一致性
3.Isolation 隔离性
4.Durability 持久性
原子性,指的是整个事务是一个独立的单元,要么操作成功,要么操作不成功
一致性,事务必须要保持和系统处于一致的状态(如果不一致会导致系统其它的方出现bug)
隔离性,事务是并发控制机制,他们的交错也需要一致性,隔离隐藏,一般通过悲观或者乐观锁实现
持久性,一个成功的事务将永久性地改变系统的状态,所以在它结束之前,所有导致状态的变化都记录在一个持久的事务日志中

114、char和varchar的区别?
char:存储定长数据很方便,CHAR字段上的索引效率级高,必须在括号里定义长度,可以有默认值,比如定义char(10),那么不论你存储的数据是否达到了10个字节,都要占去10个字节的空间(自动用空格填充),且在检索的时候后面的空格会隐藏掉,所以检索出来的数据需要记得用什么trim之类的函数去过滤空格。
varchar:存储变长数据,但存储效率没有CHAR高,必须在括号里定义长度,可以有默认值。保存数据的时候,不进行空格自动填充,而且如果数据存在空格时,当值保存和检索时尾部的空格仍会保留。另外,varchar类型的实际长度是它的值的实际长度+1,这一个字节用于保存实际使用了多大的长度。

1、经常变化的字段用varchar;
2、知道固定长度的用char;
3、超过255字节的只能用varchar或者text;
4、能用varchar的地方不用text;
5、能够用数字类型的字段尽量选择数字类型而不用字符串类型,这会降低查询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连接回逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了

115、mysql中float和double、decimal的区别?
float数值类型用于表示单精度浮点数值,而double数值类型用于表示双精度浮点数值,float和double都是浮点型,而decimal是定点型;
FLOAT和DOUBLE在不指 定精度时,默认会按照实际的精度来显示,而DECIMAL在不指定精度时,默认整数为10,小数为0。
double精度高,有效数字16位,float精度7位。但double消耗内存是float的两倍,double的运算速度比float慢得多

116、mysql中的内连接、左连接、右连接的区别?
内连接,显示两个表中有联系的所有数据;
2.左链接,以左表为参照,显示所有数据;
3.右链接,以右表为参照显示数据;

117、mysql的索引怎么实现的?
索引是一种高效获取数据的存储结构,例:hash、 二叉、 红黑
Mysql为什么不用上面三种数据结构而采用B+Tree:
若仅仅是 select * from table where id=45 , 上面三种算法可以轻易实现,但若是select * from table where id<6 , 就不好使了,它们的查找方式就类似于"全表扫描",因为他们的高度是不可控的(如下图)。B+Tree的高度是可控的,mysql通常是3到5层。注意:B+Tree只在最末端叶子节点存数据,叶子节点是以链表的形势互相指向的。

MyISAM:支持全文索引;不支持事务;它是表级锁;会保存表的具体行数.
InnoDB:5.6以后才有全文索引;支持事务;它是行级锁;不会保存表的具体行数.
聚集索引中,叶子节点的data直接包含数据;非聚集索引中,叶子节点存储数据地址的指针。
MyISAM非聚集索引,InnoDB聚集索引。

118、怎么验证mysql索引满足需求?
用explain检查下扫描行数及索引的使用情况

119、数据库的事务隔离?
① Serializable (串行化):可避免脏读、不可重复读、幻读的发生。

② Repeatable read (可重复读):可避免脏读、不可重复读的发生。

③ Read committed (读已提交):可避免脏读的发生。

④ Read uncommitted (读未提交):最低级别,任何情况都无法保证。

120、mysql常用的引擎及区别?
InnoDB:支持事务处理,支持外键,支持崩溃修复能力和并发控制。如果需要对事务的完整性要求比较高(比如银行),要求实现并发控制(比如售票),那选择InnoDB有很大的优势。如果需要频繁的更新、删除操作的数据库,也可以选择InnoDB,因为支持事务的提交(commit)和回滚(rollback)。

MyISAM:插入数据快,空间和内存使用比较低。如果表主要是用于插入新记录和读出记录,那么选择MyISAM能实现处理高效率。如果应用的完整性、并发性要求比较低,也可以使用。

MEMORY:所有的数据都在内存中,数据的处理速度快,但是安全性不高。如果需要很快的读写速度,对数据的安全性要求较低,可以选择MEMOEY。它对表的大小有要求,不能建立太大的表。所以,这类数据库只使用在相对较小的数据库表。

121、mysql行锁和表锁?
表级锁: 开销小,加锁快;不会出现死锁(因为MyISAM会一次性获得SQL所需的全部锁);锁定粒度大,发生锁冲突的概率最高,并发度最低;
行级锁: 开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高

122、mysql乐观锁和悲观锁?
悲观锁的特点是先获取锁,再进行业务操作,即“悲观”的认为获取锁是非常有可能失败的,因此要先确保获取锁成功再进行业务操作。通常来讲在数据库上的悲观锁需要数据库本身提供支持,即通过常用的select … for update操作来实现悲观锁。
乐观锁的特点先进行业务操作,不到万不得已不去拿锁。乐观锁在数据库上的实现完全是逻辑的,不需要数据库提供特殊的支持。一般的做法是在需要锁的数据上增加一个版本号,或者时间戳。

乐观锁在不发生取锁失败的情况下开销比悲观锁小,但是一旦发生失败回滚开销则比较大,因此适合用在取锁失败概率比较小的场景,可以提升系统并发性能
乐观锁还适用于一些比较特殊的场景,例如在业务操作过程中无法和数据库保持连接等悲观锁无法适用的地方

123、mysql问题排查的方法?
查看链接数
show PROCESSLIST;
通过mysql的端口定位是哪个线程占用
netstat -ntp |grep 46888
通过线程号排查是哪个应用
ps -ef | grep pid

分析sql是否属于慢查询通过是数据库的关键在EXPLAIN进行分析sql语句的性能(1、是否使用索引,2、是否查询的字段内容过大,3、查询过多的级联对表的影响);
查看mysqld进程的cpu消耗占比
确认mysql进程的cpu消耗是%user, 还是sys%高
确认是否是物理内存不够用了
确认是否有swap产生

124、mysql性能优化?
索引优化;查询字段优化;查询条件优化;表结构的设计优化;
将关联查询拆分成多个查询

125、redis是什么有哪些使用场景?
Redis是一个key-value存储系统。读写性能优异、持久化、数据类型丰富、单线程、数据自动过期、发布订阅、分布式。
场景:做缓存、分布式锁、应对海量数据和高并发、排行榜

126、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模式的数据备份;

127、redis为什么是单线程?
纯内存操作;采用单线程,避免了不必要的上下文切换和竞争条件;采用了非阻塞I/O多路复用机制;数据结构简单,对数据操作也简单;使用底层模型不同,它们之间底层实现方式以及与客户端之间通信的应用协议不一样,Redis直接自己构建了VM 机制 。

128、什么是缓存穿透、缓存雪崩、缓存击穿?怎么解决?
缓存穿透,是指查询一个数据库一定不存在的数据。
解决方法是采用缓存空值的方式。
缓存雪崩,是指在某一个时间段,缓存集中过期失效。
解决方案:一般是采取不同分类商品,缓存不同周期;或者加分布式锁,再查询一次数据库。
缓存击穿,是指一个key非常热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,就像在一个屏障上凿开了一个洞。
解决方案:设置缓存为不过期

129、redis支持的数据类型?
字符串string:是一个由字节组成的序列,他在Redis中是二进制安全的,这便意味着该类型可以接受任何格式的数据
列表list:允许用户从序列的两端推入或者弹出元素,列表由多个字符串值组成的有序可重复的序列,是链表结构,所以向列表两端添加元素的时间复杂度为0(1),获取越接近两端的元素速度就越快。
散列hash:具有String key和String value的map容器,可以将多个key-value存储到一个key中。每一个Hash可以存储4294967295个键值对。
集合set:无序不可重复的,和列表一样,在执行插入和删除和判断是否存在某元素时,效率是很高的。集合最大的优势在于可以进行交集并集差集操作。Set可包含的最大元素数量是4294967295。
应用场景:1.利用交集求共同好友。2.利用唯一性,可以统计访问网站的所有独立IP。3.好友推荐的时候根据tag求交集,大于某个threshold(临界值的)就可以推荐。
有序集合sorted set:set很像,差别在于有序集合中每一个成员都会有一个分数(score)与之关联,Redis正是通过分数来为集合中的成员进行从小到大的排序。
应用场景:可以用于一个大型在线游戏的积分排行榜,每当玩家的分数发生变化时,可以执行zadd更新玩家分数(score),此后在通过zrange获取几分top ten的用户信息。

130、Jedis和redisson的区别?
Jedis 和 Redisson 都是Java中对Redis操作的封装。Jedis 只是简单的封装了 Redis 的API库,可以看作是Redis客户端,它的方法和Redis 的命令很类似。Redisson 不仅封装了 redis ,还封装了对更多数据结构的支持,以及锁等功能,相比于Jedis 更加大。但Jedis相比于Redisson 更原生一些,更灵活。

131、怎么保证缓存和数据库数据的一致性?
给缓存设置过期时间,是保证最终一致性的解决方案;
更新数据库后要及时更新缓存、缓存失败时增加重试机制
如果你的项目对缓存的要求是强一致性的,那么请不要使用缓存。

132、redis持久化几种方式?
Redis的所有数据都是保存在内存中,然后不定期的通过异步方式保存到磁盘上(这称为“半持久化模式”);也可以把每一次数据变化都写入到一个append only file(aof)里面(这称为“全持久化模式”)。
redis提供两种方式进行持久化,一种是RDB持久化(原理是将Reids在内存中的数据库记录定时dump到磁盘上的RDB持久化),另外一种是AOF(append only file)持久化(原理是将Reids的操作日志以追加的方式写入文件)。

RDB持久化配置
Redis会将数据集的快照dump到dump.rdb文件中。此外,我们也可以通过配置文件来修改Redis服务器dump快照的频率,在打开6379.conf文件之后,我们搜索save,可以看到下面的配置信息:

save 900 1 #在900秒(15分钟)之后,如果至少有1个key发生变化,则dump内存快照。
save 300 10 #在300秒(5分钟)之后,如果至少有10个key发生变化,则dump内存快照。
save 60 10000 #在60秒(1分钟)之后,如果至少有10000个key发生变化,则dump内存快照。

AOF持久化配置
在Redis的配置文件中存在三种同步方式,它们分别是:
appendfsync always #每次有数据修改发生时都会写入AOF文件。
appendfsync everysec #每秒钟同步一次,该策略为AOF的缺省策略。
appendfsync no #从不同步。高效但是数据不会被持久化。

133、redis怎么实现分布式锁?
使用redis的SETNX实现分布式锁
SETNX是将 key 的值设为 value,当且仅当 key 不存在。若给定的 key 已经存在,则 SETNX 不做任何动作。
返回1,说明该进程获得锁,SETNX将键 lock.id 的值设置为锁的超时时间,当前时间 +加上锁的有效时间。
返回0,说明其他进程已经获得了锁,进程不能进入临界区。进程可以在一个循环中不断地尝试 SETNX 操作,以获得锁。

  1. setnx(lockkey, 当前时间+过期超时时间) ,如果返回1,则获取锁成功;如果返回0则没有获取到锁,转向2。
    2. get(lockkey)获取值oldExpireTime ,并将这个value值与当前的系统时间进行比较,如果小于当前系统时间,则认为这个锁已经超时,可以允许别的请求重新获取,转向3。
  2. 计算newExpireTime=当前时间+过期超时时间,然后getset(lockkey, newExpireTime) 会返回当前lockkey的值currentExpireTime。
  3. 判断currentExpireTime与oldExpireTime 是否相等,如果相等,说明当前getset设置成功,获取到了锁。如果不相等,说明这个锁又被别的请求获取走了,那么当前请求可以直接返回失败,或者继续重试。
  4. 在获取到锁之后,当前线程可以开始自己的业务处理,当处理完毕后,比较自己的处理时间和对于锁设置的超时时间,如果小于锁设置的超时时间,则直接执行delete释放锁;如果大于锁设置的超时时间,则不需要再锁进行处理。

134、redis如何内存优化?
一.redisObject对象
二.缩减键值对象
三.共享对象池
四.字符串优化
五.编码优化
六.控制key的数量

Redis存储的所有值对象在内部定义为redisObject结构体,内部结构如下图所示:
在这里插入图片描述
Redis存储的数据都使用redisObject来封装,包括string,hash,list,set,zset在内的所有数据类型。
1.type字段:
表示当前对象使用的数据类型,Redis主要支持5种数据类型:string,hash,list,set,zset。可以使用type {key}命令查看对象所属类型,type命令返回的是值对象类型,键都是string类型。
2.encoding字段:
表示Redis内部编码类型,encoding在Redis内部使用,代表当前对象内部采用哪种数据结构实现。理解Redis内部编码方式对于优化内存非常重要 ,同一个对象采用不同的编码实现内存占用存在明显差异,具体细节见之后编码优化部分。
3.lru字段:
记录对象最后一次被访问的时间,当配置了 maxmemory和maxmemory-policy=volatile-lru | allkeys-lru 时, 用于辅助LRU算法删除键数据。可以使用object idletime {key}命令在不更新lru字段情况下查看当前键的空闲时间。
开发提示:可以使用scan + object idletime 命令批量查询哪些键长时间未被访问,找出长时间不访问的键进行清理降低内存占用。
4.refcount字段:
记录当前对象被引用的次数,用于通过引用次数回收内存,当refcount=0时,可以安全回收当前对象空间。使用object refcount {key}获取当前对象引用。当对象为整数且范围在[0-9999]时,Redis可以使用共享对象的方式来节省内存。具体细节见之后共享对象池部分。
5. *ptr字段:
与对象的数据内容相关,如果是整数直接存储数据,否则表示指向数据的指针。Redis在3.0之后对值对象是字符串且长度<=39字节的数据,内部编码为embstr类型,字符串sds和redisObject一起分配,从而只要一次内存操作。
开发提示:高并发写入场景中,在条件允许的情况下建议字符串长度控制在39字节以内,减少创建redisObject内存分配次数从而提高性能。

降低Redis内存使用最直接的方式就是缩减键(key)和值(value)的长度。
当使用Redis存储大量数据时,通常会存在大量键,过多的键同样会消耗大量内存。
对于存储相同的数据内容利用Redis的数据结构降低外层键的数量,也可以节省大量内存。如下图所示,通过在客户端预估键规模,把大量键分组映射到多个hash结构中降低键的数量。

Redis所有数据都采用key-value数据类型,每次创建键值对时,至少创建两个类型对象:key对象和value对象。内存消耗可以简单的理解为sizeof(keys)+sizeof(values)。键对象都是字符串,在使用Redis时很容易忽略键对内存消耗的影响,应当避免使用过长的键。

135、redis淘汰策略有哪些?
noeviction:达到内存限额后返回错误,客户尝试可以导致更多内存使用的命令(大部分写命令,但DEL和一些例外)
allkeys-lru:为了给新增加的数据腾出空间,驱逐键先试图移除一部分最近使用较少的(LRC)。
volatile-lru:为了给新增加的数据腾出空间,驱逐键先试图移除一部分最近使用较少的(LRC),但只限于过期设置键。
allkeys-random: 为了给新增加的数据腾出空间,驱逐任意键
volatile-random: 为了给新增加的数据腾出空间,驱逐任意键,但只限于有过期设置的驱逐键。
volatile-ttl: 为了给新增加的数据腾出空间,驱逐键只有秘钥过期设置,并且首先尝试缩短存活时间的驱逐键

我们可以设置maxmemory ,当数据达到限定大小后,会选择配置的策略淘汰数据maxmemory-policy

136、redis常见性能问题和解决方案?
1.Master最好不要做任何持久化工作,包括内存快照和AOF日志文件,特别是不要启用内存快照做持久化。

2.如果数据比较关键,某个Slave开启AOF备份数据,策略为每秒同步一次。

3.为了主从复制的速度和连接的稳定性,Slave和Master最好在同一个局域网内。

4.尽量避免在压力较大的主库上增加从库

5.为了Master的稳定性,主从复制不要用图状结构,用单向链表结构更稳定,即主从关系为:Master<–Slave1<–Slave2<–Slave3…,这样的结构也方便解决单点故障问题,实现Slave对Master的替换,也即,如果Master挂了,可以立马启用Slave1做Master,其他不变。

137、JVM的组成及作用?
虚拟机栈(通常称为Java栈)、本地方法栈(储存JNI)、程序计数器、方法区、堆、直接内存

虚拟机栈:每一个方法在执行的同时都会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行完成的过程,对应着一个栈帧在虚拟机栈种入栈到出栈的过程。
本地方法栈:原理基本同虚拟机栈相同,区别在于虚拟机栈是为虚拟机执行java方法服务,而本地方法栈是为虚拟机执行Native方法服务
程序计数器:一块较小的内存空间,是当前线程所执行的字节码的行号指示器。

方法区:各线程共享的区域,方法区存储一杯虚拟机加载的类信息、常量、静态变量、即使编译器遍以后的代码等数据。
堆:堆中有句柄池和类的实例对象。堆是所有线程共享的一块内存区域,在虚拟机启动时创建。
直接内存:本机直接内存分配不受到Java堆大小的限制,但是,既然是内存,肯定会受到本机总内存大小以及处理器寻址空间的限制。

138、JVM 堆和栈的区别?
栈内存:程序在栈内存中运行;栈中存的是基本数据类型和堆中对象的引用;栈是运行时的单元;栈解决程序的运行问题,即程序如何执行,或者说如何处理数据;一个线程一个独立的线程栈。
堆内存:程序运行所需的大部分数据保存在栈内存中;堆中存的是对象;堆是存储的单元,堆只是一块共享的内存;堆解决的是数据存储的问题,即数据怎么放,放在哪儿;所有线程共享堆内存。

139、双亲委派模型?
Java虚拟机先从最核心的API开始查找,防止不可信的类扮演被信任的类。
启动类加载器 Bootstrap ClassLoader:加载<JAVA_HOME>\lib目录下核心库
扩展类加载器 Extension ClassLoader:加载<JAVA_HOME>\lib\ext目录下扩展包
应用程序类加载器 Application ClassLoader: 加载用户路径(classpath)上指定的类库
1.当Application ClassLoader 收到一个类加载请求时,他首先不会自己去尝试加载这个类,而是将这个请求委派给父类加载器Extension ClassLoader去完成。
2.当Extension ClassLoader收到一个类加载请求时,他首先也不会自己去尝试加载这个类,而是将请求委派给父类加载器Bootstrap ClassLoader去完成。
3.如果Bootstrap ClassLoader加载失败(在<JAVA_HOME>\lib中未找到所需类),就会让Extension ClassLoader尝试加载。
4.如果Extension ClassLoader也加载失败,就会使用Application ClassLoader加载。
5.如果Application ClassLoader也加载失败,就会使用自定义加载器去尝试加载。
6.如果均加载失败,就会抛出ClassNotFoundException异常。

139、类加载的执行过程?
类从被加载到JVM中开始,到卸载为止,整个生命周期包括:加载、验证、准备、解析、初始化、使用和卸载七个阶段。
其中类加载过程包括加载、验证、准备、解析和初始化五个阶段。
类加载器的任务就是根据一个类的全限定名来读取此类的二进制字节流到JVM中,然后转换为一个与目标类对应的java.lang.Class对象实例。
链接阶段要做的是将加载到JVM中的二进制字节流的类数据信息合并到JVM的运行时状态中,经由验证、准备和解析三个阶段。
将一个类中所有被static关键字标识的代码统一执行一遍,如果执行的是静态变量,那么就会使用用户指定的值覆盖之前在准备阶段设置的初始值;如果执行的是static代码块,那么在初始化阶段,JVM就会执行static代码块中定义的所有操作。

140、怎么判断对象是否可以被回收?
算法的基本思想是通过一系列的成为“GC Roots”的对象作为起点,从这些起点开始向下搜索,搜索的路径就成为引用链(Reference Chain),当一个对象到GC Roots没有任何的引用链相连的话,也就是该对象不可达,则证明该对象是不可用的。
在Java中GC Roots对象包括以下几个:
虚拟机栈(栈帧的本地变量表)中引用的对象
方法区中类静态属性引用的对象
方法区中常量引用的对象
本地方法栈JNI引用的对象

在可达性的算法中,至少要被标记两次,才会真正的宣告一个对象死亡:如果对象那在进行可达性分析发现没有GC Roots相连的引用链,那么将会被第一次标记并且进行一次筛选,筛选的条件是此对象那个是否有必要执行finalize()方法。当对象没有覆盖finalize()方法,或者finalize()方法已经被虚拟机调用过,虚拟机将这两种情况都视为“没有必要执行”。

141、java中有哪些引用类型?
强引用、软引用、弱引用、虚引用

引用队列可以与软引用、弱引用以及虚引用一起配合使用,当垃圾回收器准备回收一个对象时,如果发现它还有引用,那么就会在回收对象之前,把这个引用加入到与之关联的引用队列中去。程序可以通过判断引用队列中是否已经加入了引用,来判断被引用的对象是否将要被垃圾回收,这样就可以在对象被回收之前采取一些必要的措施。
与软引用、弱引用不同,虚引用必须和引用队列一起使用。

142、jvm有哪些垃圾回收算法?
对象是否“已死”算法——可达性分析算法
标记-清除算法
复制算法(Java堆中新生代的垃圾回收算法)
标记-压缩算法(或称为标记-整理算法,Java堆中老年代的垃圾回收算法)

143、jvm有哪些垃圾回收器?
在这里插入图片描述
Serial收集器、ParNew收集器、Parallel Scavenge(并行回收)收集器、Serial Old 收集器、Parallel Old 收集器、CMS收集器、G1收集器

CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。目前很大一部分的Java应用集中在互联网站或者B/S系统的服务端上,这类应用尤其重视服务器的响应速度,希望系统停顿时间最短,以给用户带来较好的体验。CMS收集器就非常符合这类应用的需求。
CMS收集器是基于“标记-清除”算法实现的。它的运作过程相对前面几种收集器来说更复杂一些,整个过程分为4个步骤:
(1)初始标记
(2)并发标记
(3)重新标记
(4)并发清除
其中,初始标记、重新标记这两个步骤仍然需要“Stop The World”.
CMS收集器主要优点:并发收集,低停顿。

CMS三个明显的缺点:

(1)CMS收集器对CPU资源非常敏感。CPU个数少于4个时,CMS对于用户程序的影响就可能变得很大,为了应付这种情况,虚拟机提供了一种称为“增量式并发收集器”的CMS收集器变种。所做的事情和单CPU年代PC机操作系统使用抢占式来模拟多任务机制的思想

(2)CMS收集器无法处理浮动垃圾,可能出现“Concurrent Mode Failure”失败而导致另一次Full GC的产生。在JDK1.5的默认设置下,CMS收集器当老年代使用了68%的空间后就会被激活,这是一个偏保守的设置,如果在应用中蓝年代增长不是太快,可以适当调高参数-XX:CMSInitiatingOccupancyFraction的值来提高触发百分比,以便降低内存回收次数从而获取更好的性能,在JDK1.6中,CMS收集器的启动阀值已经提升至92%。

(3)CMS是基于“标记-清除”算法实现的收集器,手机结束时会有大量空间碎片产生。空间碎片过多,可能会出现老年代还有很大空间剩余,但是无法找到足够大的连续空间来分配当前对象,不得不提前出发FullGC。为了解决这个问题,CMS收集器提供了一个-XX:+UseCMSCompactAtFullCollection开关参数(默认就是开启的),用于在CMS收集器顶不住要进行FullGC时开启内存碎片合并整理过程,内存整理的过程是无法并发的,空间碎片问题没有了,但停顿时间变长了。虚拟机设计者还提供了另外一个参数-XX:CMSFullGCsBeforeCompaction,这个参数是用于设置执行多少次不压缩的Full GC后,跟着来一次带压缩的(默认值为0,标识每次进入Full GC时都进行碎片整理)

对象的分配策略。它分为3个阶段:
TLAB(Thread Local Allocation Buffer)线程本地分配缓冲区
Eden区中分配
Humongous区分配

G1收集器:
G1在运行过程中主要包含如下4种操作方式:
YGC(不同于CMS)
并发阶段
混合模式
full GC (一般是G1出现问题时发生)

144、jvm分代垃圾回收器怎么工作?
为了提高垃圾回收的效率,我们把生命周期不同的对象分代处理。
垃圾回收机制根据对象的生命周期不同划分为了三个代:年轻代、年老代、持久代
由于对象进行了分代处理,因此垃圾回收区域、时间也不一样。GC有两种类型:Scavenge GC和Full GC。

1.        创建新对象,大多数放在Eden区
2.        Eden满了(或达到一定比例),触发Minor GC,   把有用的复制到Survivor1, 同时清空Eden区。
3.        Eden区再次满了,出发Minor GC, 把Eden和Survivor1中有用的,复制到Survivor2, 同时清空Eden,Survivor1。
4.        Eden区第三次满了,出发Minor GC, 把Eden和Survivor2中有用的,复制到Survivor1, 同时清空Eden,Survivor2。 形成循环,Survoivor1和Survivor中来回清空、复制,过程中有一个Survivor处于空的状态用于下次复制的。
5.        重复多次(默认15),没有被Survivor清理的对象,复制到Old(Tenuerd)区.
6.        当Old达到一定比例,触发Major GC,清理老年代。        
7.        当Old满了,触发Full GC。注意,Full GC清理代价大,系统资源消耗高。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

145、jvm调优工具?
jvm监控分析工具一般分为两类,一种是jdk自带的工具,一种是第三方的分析工具。
我们最常使用的只有两款:jconsole.exe和jvisualvm.exe;第三方的分析工具有很多,各自的侧重点不同,比较有代表性的:MAT(Memory Analyzer Tool)、GChisto等。

146、常用的jvm调优参数?
一、Trace跟踪参数(跟踪GC、类、变量的内存变化情况)
-verbose:gc 或 -XX:+printGC 或 -XX:+printGCDetails、-XX:+TraceClassLoading
二、堆的分频参数
-Xmx10M 指定最大堆,JVM最多能够使用的堆空间 (超过该空间引发OOM)
-Xms5M 指定最小堆,JVM至少会有的堆空间(尽可能维持在最小堆)
-Xmn 11M(new) 设置新生代大小
官方推荐:新生代占堆空间3/8;幸存代占新生代1/10
三、栈的分配参数
-Xss 每个线程都有独立的栈空间(几百k,比较小)
需要大量线程时,需要尽可能减小栈空间
栈空间太小-----StackOverFlow栈溢出

147、为什么CMS两次标记时要 stop the world?
第一次标记root对象,必须要stw(初始标记也会扫描新生代);当GC线程标记好了一个对象的时候,此时我们程序的线程又将该对象重新加入了“关系网”中,当执行二次标记的时候,该对象也没有重写finalize()方法,因此回收的时候就会回收这个不该回收的对象。
  虚拟机的解决方法就是在一些特定指令位置设置一些“安全点”,当程序运行到这些“安全点”的时候就会暂停所有当前运行的线程(Stop The World 所以叫STW),暂停后再找到“GC Roots”进行关系的组建,进而执行标记和清除。
  这些特定的指令位置主要在:
1、循环的末尾
2、方法临返回前 / 调用方法的call指令后
3、可能抛异常的位置

148、liunx下统计文件行数?
wc -l file.txt

149、liunx查询文件尾部200包含order的信息?
tail -n 200 filename | grep order

150、Dubbo是什么?
Dubbo是阿里巴巴开源的基于 Java 的高性能 RPC 分布式服务框架。

151、为什么要用Dubbo?
是阿里开源项目,国内很多互联网公司都在用,已经经过很多线上考验。内部使用了 Netty、Zookeeper,保证了高性能高可用性。

152、Dubbo需要 Web 容器吗?
不需要,如果硬要用 Web 容器,只会增加复杂性,也浪费资源

153、Dubbo里面有哪几种节点角色?
provider 服务提供 consumer 服务消费 registry 服务注册中心
monitor 监控中心 container 服务运行容器

154、服务注册与发现的流程图
在这里插入图片描述

155、Dubbo默认使用什么注册中心,还有别的选择吗?
推荐使用 Zookeeper 作为注册中心,还有 Redis、Multicast、Simple 注册中心,但不推荐。

156、Dubbo 核心的配置有哪些?之间的关系
在这里插入图片描述
在这里插入图片描述

157、在 Provider 上可以配置的 Consumer 端的属性有哪些?
1)timeout:方法调用超时
2)retries:失败重试次数,默认重试 2 次
3)loadbalance:负载均衡算法,默认随机
4)actives 消费者端,最大并发调用限制

158、Dubbo启动时如果依赖的服务不可用会怎样?
Dubbo 缺省会在启动时检查依赖的服务是否可用,不可用时会抛出异常,阻止 Spring 初始化完成,默认 check=“true”,可以通过 check=“false” 关闭检查。

159、Dubbo推荐使用什么序列化框架,你知道的还有哪些?
推荐使用Hessian序列化,还有Duddo、FastJson、Java自带序列化

160、Dubbo默认使用的是什么通信框架,还有别的选择吗?
Dubbo 默认使用 Netty 框架,也是推荐的选择,另外内容还集成有Mina、Grizzly。

161、Dubbo有哪几种集群容错方案,默认是哪种?
在这里插入图片描述

162、Dubbo有哪几种负载均衡策略,默认是哪种?
在这里插入图片描述

163、当一个服务接口有多种实现时怎么做?
当一个接口有多种实现时,可以用 group 属性来分组,服务提供方和消费方都指定同一个 group 即可

164、Dubbo支持服务多协议吗?
Dubbo 允许配置多协议,在不同服务上支持不同协议或者同一服务上同时支持多种协议。

165、注册了多个同一样的服务,如果测试指定的某一个服务呢?
可以配置环境点对点直连,绕过注册中心,将以服务接口为单位,忽略注册中心的提供者列表。

166、服务上线怎么兼容旧版本?
可以用版本号(version)过渡,多个不同版本的服务注册到注册中心,版本号不同的服务相互间不引用。这个和服务分组的概念有一点类似。

167、Dubbo可以对结果进行缓存吗?
可以,Dubbo 提供了声明式缓存,用于加速热门数据的访问速度,以减少用户加缓存的工作量

168、Dubbo服务之间的调用是阻塞的吗?
默认是同步等待结果阻塞的,支持异步调用。
Dubbo 是基于 NIO 的非阻塞实现并行调用,客户端不需要启动多线程即可完成并行调用多个远程服务,相对多线程开销较小,异步调用会返回一个 Future 对象。
在这里插入图片描述

169、Dubbo支持分布式事务吗?
目前暂时不支持

170、Dubbo的管理控制台能做什么?
管理控制台主要包含:路由规则,动态配置,服务降级,访问控制,权重调整,负载均衡,等管理功能。

171、说说 Dubbo 服务暴露的过程
Dubbo 会在 Spring 实例化完 bean 之后,在刷新容器最后一步发布 ContextRefreshEvent 事件的时候,通知实现了 ApplicationListener 的 ServiceBean 类进行回调 onApplicationEvent 事件方法,Dubbo 会在这个方法中调用 ServiceBean 父类 ServiceConfig 的 export 方法,而该方法真正实现了服务的(异步或者非异步)发布。

172、如何设计一个秒杀系统?
什么是秒杀:在一定的时间内几秒或者几分钟,对一定数量的库存进行出卖。
1,在秒杀之前,比如上午十点开始秒杀,很多用户可能在九点五十左右就开始访问自己心仪的秒杀商品,这样就会出现在秒杀之前用很多的并发量,所以在秒杀之前的半个小时之前,是否可以将参加秒杀活动商品的一些信息缓存起来,这样就可以减小因为高并发访问,给数据库带来的压力。
2,有的用户为了抢到商品可能利用第三插件,去频繁的访问接口,这样给接口会带来很大的压力,为了避免这种刻意的刷单问题,可以在后台对同一个用户的访问频率做限制,可以预测接口的实际访问频率,然后对不同的接口,同一个用户做频率限制,如某个抢购入口,可以设置一个用户一分钟不能访问超过60次,10秒内不能超过20次等不同时段不同访问频率策略,这个可以通过redis等缓存框架做到,列入以某个接口+用户唯一性标准为key,可以选择value为string类型,如果缓存更多数据,value可以选择hash类型,value的值是int类型,这样用户每次访问接口,可以先判断该值有没有达到预设的访问频率限制的值,如果达到了,就告诉用户,你的访问太过频繁,请多长时间后再试,或者要求用户输入验证码(图片验证码或者短信验证码)。如果没有达到预设值,就给int值技术加一,在第一次访问的时候,即查询的前exist判断,如果不存在,插入第一条数据,并且设置过气时间,这个时间就是访问频率的时间限制例如一分钟只能访问60次,那么这里的过期时间就是60秒,预设值就是60次。这样就可以从一定程度上避免刷单问题。
3,一个用户可能当初注册了很多的账号,平时不用,专门用来参加秒杀活动,这样其实也会造成系统压力。解决方式和上述差不多,只是对ip做限制,但是怎样做可能伤到真实的用户,因为有的场合如网吧,里面人购物其实是同一个ip出口,这个时候,其实也可以对用户的等级做限制,只有多高的等级才可以参加秒杀活动。

秒杀场景的特点:
同一时间同时进行抢购,网站瞬时访问流量激增。
访问请求数量远远大于库存数量,但是只有少部分用户能够秒杀成功。
秒杀业务流程比较简单,一般就是下订单减库存

秒杀设计思路:
前端:页面静态化,禁止重复提交。

后端:可拓展,缓存,限流,削峰,异步处理
可拓展:服务的可扩展,可以水平添加机器将用户请求分担到不同的机器上去。数据库可扩展,支持分库分表,对于用户的请求,映射到不同的数据库,减少单台数据库的压力。
内存缓存:参加秒杀系统的商品是事先可知的,可以将参加秒杀的商品信息事先缓存到redis等缓存系统中,这样可以大大的提高系统的吞吐量,减少关系型数据库的读写压力。
限流: 一单秒杀开始,实际秒杀成功的用户只是库存的数量,在库存没有之后,将前端的秒杀入口关闭。
削峰:数据库削峰。对于秒杀系统瞬时会有大量用户涌入,所以在抢购一开始会有很高的瞬间峰值。对于关系型数据库而言,这个是致命的,是压垮系统很重要的原因,所以如何把瞬间的高流量变成一段时间平稳的流量也是设计秒杀系统很重要的思路。实现削峰的常用的方法有利用缓存和消息中间件等技术。
异步处理:秒杀系统是一个高并发系统,采用异步处理模式可以极大地提高系统并发量,其实异步处理就是削峰的一种实现方式。

利用redis+mysql实现简单的秒杀系统
Redis是一个分布式key-value缓存系统,value支持多种数据结构,这里value可以选择两种类型,String(或者hash):主要用于记录商品的库存,对商品减库存。Set集合(这里不要用list集合,list集合是可重复的,set是不可重复的,可以保证一个用户只卖一次,如果一个用户可以买多次那么可以使用list集合):用于存储用户的id获取其他唯一确定一个用户的值。

在秒杀开始的前:可以使用批处理,将参加秒杀的产品信息缓存到redis中。这里将产品的业务唯一字段作为key,库存作为value。这里的key要和前端缓存的key一致。
在秒杀开始时::用户大量提交。根据用户提交的产品信息,获取到redis中需要的key值,查询缓存(为了保证缓存有效,如果第一次没有查询到,可以到数据库查询,然后在缓存一下,不过一般不会出现),得到库存量,判断当前库存是否大于零,如果大于零,判断当前的set集合中是否用该用户ID,如果没有,减库存并且将用户的ID放入集合中,并对库存减一,如果库存为0,提示用户,商品已售完等文案信息,如果集合中已经存在该用户id,则不做任何处理,直接处理下一个请求。直到最后库存售完,上面的过程可以利用redis事务和watch功能完成对数据一致性的控制即超卖问题。
库存售完后:程序开始启动一个有个后台线程,可以阻塞等待商品库存售完的通知,在上面一步,库存一旦售完,后台进程获取set集合中的用户信息,异步处理需要操作的购买等后续操作。

这只是一个简单的秒杀系统,实际的秒杀系统,还要考虑到很多的真实场景需要很多完善的地方,希望大家一起讨论如何设计一个秒杀系统。

173、内存溢出可能原因和解决?
原因可能是A,数据加载过多,如1次从数据库中取出过多数据 B,集合类中有对对象的引用,用完后没有清空或者集合对象未置空导致引用存在等,是的JVM无法回收 C,死循环,过多重复对象 D,第三方软件的bug E,启动参数内存值设定的过小。

174、幂等的处理方式?
一、查询与删除操作是天然幂等
二、唯一索引,防止新增脏数据
三、token机制,防止页面重复提交
四、悲观锁 for update
五、乐观锁(通过版本号/时间戳实现, 通过条件限制where avai_amount-#subAmount# >= 0)
六、分布式锁
七、状态机幂等(如果状态机已经处于下一个状态,这时候来了一个上一个状态的变更,理论上是不能够变更的,这样的话,保证了有限状态机的幂等。)
八、select + insert(并发不高的后台系统,或者一些任务JOB,为了支持幂等,支持重复执行)

175、RabbitMQ消息堆积怎么处理?
增加消费者的处理能力(例如优化代码),或减少发布频率
单纯升级硬件不是办法,只能起到一时的作用
考虑使用队列最大长度限制,RabbitMQ 3.1支持
给消息设置年龄,超时就丢弃
默认情况下,rabbitmq消费者为单线程串行消费,设置并发消费两个关键属性concurrentConsumers和prefetchCount,concurrentConsumers设置的是对每个listener在初始化的时候设置的并发消费者的个数,prefetchCount是每次一次性从broker里面取的待消费的消息的个数
建立新的queue,消费者同时订阅新旧queue
生产者端缓存数据,在mq被消费完后再发送到mq
打破发送循环条件,设置合适的qos值,当qos值被用光,而新的ack没有被mq接收时,就可以跳出发送循环,去接收新的消息;消费者主动block接收进程,消费者感受到接收消息过快时主动block,利用block和unblock方法调节接收速率,当接收线程被block时,跳出发送循环。
新建一个topic,partition是原来的10倍;然后写一个临时的分发数据的consumer程序,这个程序部署上去消费积压的数据,消费之后不做耗时的处理,直接均匀轮询写入临时建立好的10倍数量的queue;接着临时征用10倍的机器来部署consumer,每一批consumer消费一个临时queue的数据;等快速消费完积压数据之后,得恢复原先部署架构,重新用原先的consumer机器来消费消息;

176、负载均衡算法?
常见6种负载均衡算法:轮询,随机,源地址哈希,加权轮询,加权随机,最小连接数。
nginx5种负载均衡算法:轮询,weight,ip_hash,fair(响应时间),url_hash
dubbo负载均衡算法:随机,轮询,最少活跃调用数,一致性Hash

177、ThreadPoolExecutor内部工作原理?
先查看当前运行状态,如果不是RUNNING 状态会拒绝执行任务,如果是RUNNING状态,就会查看当前运行的线程数量,如果小于核心线程数,会创建新的线程来执行这个任务,如果不小于核心线程,会将这个任务放到阻塞队列去等代执行,直到上一个任务执行完再来执行这个任务。如果失败会创建一个非核心线程来执行这个任务如果当前线程数大于最大线程数,会直接拒绝该任务。

178、mysql数据库锁表怎么解决?
当前运行的所有事务
select * from information_schema.innodb_trx
当前出现的锁
select * from information_schema.innodb_locks
锁等待的对应关系
select * from information_schema.innodb_lock_waits
通过 select * from information_schema.innodb_trx 查询 trx_mysql_thread_id然后执行 kill 线程ID
KILL 8807;//后面的数字即时进程的ID

179、Spring+MyBatis实现读写分离简述?
方案一:通过MyBatis配置文件创建读写分离两个DataSource,每个SqlSessionFactoryBean对象的mapperLocations属性制定两个读写数据源的配置文件。将所有读的操作配置在读文件中,所有写的操作配置在写文件中。
方案二:通过Spring AOP在业务层实现读写分离,在DAO层调用前定义切面,利用Spring的AbstractRoutingDataSource解决多数据源的问题,实现动态选择数据源
方案三:通过Mybatis的Plugin在业务层实现数据库读写分离,在MyBatis创建Statement对象前通过拦截器选择真正的数据源,在拦截器中根据方法名称不同(select、update、insert、delete)选择数据源。
方案四:通过spring的AbstractRoutingDataSource和mybatis Plugin拦截器实现非常友好的读写分离,原有代码不需要任何改变。推荐第四种方案

这里转载的实现,可以试试https://www.jianshu.com/p/2222257f96d3

180、redis主从复制?
可以通过执行SLAVEOF命令或者设置slaveof选项,让一个服务器去复制(replicate)另一个服务器,我们称呼被复制的服务器为主服务器(master),而对主服务器进行复制的服务器则被称为从服务器(slave)
假设现在有两个Redis服务器,地址分别为127.0.0.1:6379和127.0.0.1:12345,如果我们向服务器127.0.0.1:12345发送以下命令:
127.0.0.1:12345> SLAVEOF 127.0.0.1 6379
那么服务器127.0.0.1:12345将成为127.0.0.1:6379的从服务器,而服务器127.0.0.1:6379则会成为127.0.0.1:12345的主服务器。

只有一个主 redis,可以有多个从 redis;
主从复制不会阻塞 master,在同步数据时,master 可以继续处理 client 请求;
一个 redis 可以即是主又是从。
主从配置:主 redis 配置无需特殊配置;从redis配置修改从 redis 服务器上的 redis.conf 文件,添加 slaveof 主 redisip 主 redis 端口(slaveof 192.168.0.1 6379)

复制过程说明:slave 服务启动,slave 会建立和 master 的连接,发送 sync 命令;master 启动一个后台进程将数据库快照保存到 RDB 文件中;master 就发送 RDB 文件给 slave;slave 将文件保存到磁盘上,然后加载到内存恢复;master 把缓存的命令转发给 slave。

181、redis集群搭建?
redis集群采用P2P模式,是完全去中心化的,不存在中心节点或者代理节点;
redis集群是没有统一的入口的,客户端(client)连接集群的时候连接集群中的任意节点(node)即可,集群内部的节点是相互通信的(PING-PONG机制),每个节点都是一个redis实例;
redis-cluster有这么一个投票容错机制:如果集群中超过半数的节点投票认为某个节点挂了,那么这个节点就挂了(fail)。这是判断节点是否挂了的方法;
如果集群中任意一个节点挂了,而且该节点没有从节点(备份节点),那么这个集群就挂了。这是判断集群是否挂了的方法;
因为集群内置了16384个slot(哈希槽),并且把所有的物理节点映射到了这16384[0-16383]个slot上,或者说把这些slot均等的分配给了各个节点。当需要在Redis集群存放一个数据(key-value)时,redis会先对这个key进行crc16算法,然后得到一个结果。再把这个结果对16384进行求余,这个余数会对应[0-16383]其中一个槽,进而决定key-value存储到哪个节点中。所以一旦某个节点挂了,该节点对应的slot就无法使用,那么就会导致集群无法正常工作。
每个Redis集群理论上最多可以有16384个节点

Redis集群至少需要3个节点,因为投票容错机制要求超过半数节点认为某个节点挂了该节点才是挂了,所以2个节点无法构成集群。
要保证集群的高可用,需要每个节点都有从节点,也就是备份节点,所以Redis集群至少需要6台服务器。

通过配置文件来启动3个不同的Redis实例,由于Redis默认端口为6379,所以这里使用了6380、6381、6382来运行3个Redis实例。
配置文件中以下两种保存日志的方式(保存在文件中、保存到System Log中)请根据需求选择其中一种即可:

loglevel notice #日志的记录级别,notice是适合生产环境的
  logfile “D:/Redis/Logs/redis6380_log.txt” #指定log的保持路径,默认是创建在Redis安装目录下,如果有子目录需要手动创建,如此处的Logs目录
  syslog-enabled yes #是否使用系统日志   
  syslog-ident redis6380 #在系统日志的标识名

redis.6380.conf 内容如下:
port 6380
loglevel notice
logfile “D:/Redis/Logs/redis6380_log.txt”
appendonly yes
appendfilename “appendonly.6380.aof”
cluster-enabled yes
cluster-config-file nodes.6380.conf
cluster-node-timeout 15000
cluster-slave-validity-factor 10
cluster-migration-barrier 1
cluster-require-full-coverage yes

redis.6381.conf 内容如下:
port 6381
loglevel notice
logfile “D:/Redis/Logs/redis6381_log.txt”
appendonly yes
appendfilename “appendonly.6381.aof”
cluster-enabled yes
cluster-config-file nodes.6381.conf
cluster-node-timeout 15000
cluster-slave-validity-factor 10
cluster-migration-barrier 1
cluster-require-full-coverage yes

redis.6382.conf 内容如下:
port 6382
loglevel notice
logfile “D:/Redis/Logs/redis6382_log.txt”
appendonly yes
appendfilename “appendonly.6382.aof”
cluster-enabled yes
cluster-config-file nodes.6382.conf
cluster-node-timeout 15000
cluster-slave-validity-factor 10
cluster-migration-barrier 1
cluster-require-full-coverage yes

下载并安装ruby;下载ruby环境下Redis的驱动
下载Redis官方提供的创建Redis集群的ruby脚本文件redis-trib.rb
使用redis-trib.rb来创建Redis集群:
redis-trib.rb create --replicas 0 127.0.0.1:6380 127.0.0.1:6381 127.0.0.1:6382
检验是否真的创建成功,输入以下命令:redis-trib.rb check 127.0.0.1:6380

182、斐波那契数列的实现?
public static int add(int num) {//递归
if (num == 1 || num == 2) return 1;
return add(num - 1) + add(num - 2);
}

public static int add3(int first, int second, int num) {//递归的优化版 (num要比实际数加一,从0开始
if (num < 1) {
return 0;
} else if (num == 2 || num == 1) {
return 1;
} else if (num == 3) {
return first + second;
} else {
return add3(second, first + second, num - 1);
}
}

public static int add2(int num) {//非递归
if (num == 1 || num == 2) return 1;
int first = 1;
int second = 1;
int temp = 0;
for (int i = 3; i <= num; i++) {
temp = first + second;
first = second;
second = temp;
}
return second;
}

183、Redis相比memcached有哪些优势?
memcached所有的值均是简单的字符串,redis作为其替代者,支持更为丰富的数据类型;
redis的速度比memcached快很多;
redis可以持久化其数据,而Memecache把数据全部存在内存之中;
Memcached是多线程,非阻塞IO复用的网络模型;Redis使用单线程的IO复用模型

Redis的全称是Remote Dictionary Server;支持String、List、Set、Sorted Set、hashes

184、分布式系统唯一ID生成方案
转载https://blog.csdn.net/yeyazhishang/article/details/81564520
uuid(UUID往往是使用字符串存储,查询的效率比较低,没有排序,无法保证趋势递增)
Redis生成ID:可以用Redis的原子操作 INCR和INCRBY来实现。
Twitter的snowflake算法:结果是一个long型的ID。其核心思想是:使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是0。

private RedisTemplate mRedisTemp;

public long generate(String key) {
    RedisAtomicLong counter = new RedisAtomicLong(key,mRedisTemp.getConnectionFactory());
    return counter.incrementAndGet();
}

public long generate(String key,Date expireTime) {
    RedisAtomicLong counter = new RedisAtomicLong(key, mRedisTemp.getConnectionFactory());
    counter.expireAt(expireTime);
    return counter.incrementAndGet();
}

/**
 * 获取能按固定步长增长的有过期时间的ID
 * @param key
 * @param increment
 * @return
 */
public long generate(String key,int increment,Date expireTime) {
    RedisAtomicLong counter = new RedisAtomicLong(key, mRedisTemp.getConnectionFactory());
    counter.expireAt(expireTime);
    return counter.addAndGet(increment);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

185、Paxos算法
paxos算法是基于消息传递且具有高度容错特性的一致性算法。是目前公认的解决分布式一致性问题最有效的算法之一。
一致性算法: 确保这些被提议的值中有且只有一个被选中. (如果没有值被提出, 那么就没有值会被选中.) 如果一个值被选中, 那么每个进程必须要可以感知到.

提议者(proposer): 进行提议的角色
批准者(acceptor): 通过提议的角色
学习者(learner): 感知(learn)被选中的提议

P1. 一个Acceptor必须批准它收到的第一个提案
P2. 如果一个值为v的提案被选中, 那么更高编号的被选中的提案的值必须也为v
P2a. 如果值为v的提案被选中, 那么后续任何acceptor能批准的更高版本的提案都必须要有值v.
P2b. 如果值为v的提案被选中, 那么后续任意的proposer所起草的更高编号的提案的值必须也是v.
P2c. 对于任意的N和V, 如果[N, V]被提出, 那么肯定存在一个由半数以上(majority)的acceptor组织的集合S, 满足下面两个条件之一
(a) S中不存在任何批准过编号小于N的提案的Acceptor
(b) S中所有Acceptor批准的编号小于N的提案中编号最大的值为V

总结:满足p1&P2c我们就能够确保一致性算法的安全性。
在这里插入图片描述

如何保证P2c成立
要维护P2c的成立, 一个proposer在起草提案[n, x]之前必须要先知道 (某个majority中) 各个acceptor目前通过的小于n最高的提案. 这很容易, 但是这个可能是变化的, 如何预测将来就比较困难了. 和上面P2a到P2b的思路类似, 相较于直接预测将来, proposer通过向acceptor们索取承诺来解决这个问题. 换句话说, proposer请求acceptor们不要再通过任何低于n的提案了.
于是我们有了下面的起草提案的算法:
proposer选择一个新的编号n, 并发送给 (某个majority中) 每个acceptor, 要它做出如下回应:
(a) 承诺不会再通过任何比n小的提案
(b) 小于n的最大编号的提案(如有)
如果proposer受到了绝大多数acceptor的响应, 那么它就可以起草一个提案. 提案的编号是n, 值是根据 1 中的 (b) 里面响应的提案的值来的(如果没有提案, 或者提案值为空, 那么这个proposer可以用任意值)
上面提到的proposer向acceptor发起的请求我们称之为prepare request.
当proposer经历了上面过程, 并起草了提案之后, 它就可以向 (某个majority中) acceptor们发送这个提案并等待它们审批. (注: 并不一定是上面prepare request发给的那个majority集合.) 这个请求被称为accept request.
如何保证P1成立

  1. acceptor可以在任意时刻响应prepare request;
  2. acceptor可以在不违背响应prepare request的前提下, 响应(通过)任何accept request
    所以对于acceptor来说可以概括为:
    P1a. 一个acceptor可以通过一个proposal [n, v], 当且仅当它没有响应过任何编号大于n的prepare request.
    很明显P1a => P1
    所以Paxos可以保证P2c & P1, 这样我们就得到了一个一致性的算法!

在这里插入图片描述

186、几种经典的hash算法

  1. Hash的主要原理就是把大范围映射到小范围;所以,你输入的实际值的个数必须和小范围相当或者比它更小。不然冲突就会很多。
  2. 由于Hash逼近单向函数;所以,你可以用它来对数据进行加密。
  3. 不同的应用对Hash函数有着不同的要求;比如,用于加密的Hash函数主要考虑它和单项函数的差距,而用于查找的Hash函数主要考虑它映射到小范围的冲突率。
    加法Hash:就是把输入元素一个一个的加起来构成最后的结果;
    位运算Hash:利用各种位运算(常见的是移位和异或)来充分的混合输入元素。
    乘法Hash:利用了乘法的不相关性(String的hashCode计算)
    除法Hash:因为除法太慢,这种方式几乎找不到真正的应用;
    查表Hash:查表Hash最有名的例子莫过于CRC系列算法
    混合Hash:混合Hash算法利用了以上各种方式。各种常见的Hash算法,比如MD5、Tiger都属于这个范围
    虽说以上的hash能极大程度地避免冲突,但是冲突是在所难免的。所以无论用哪种hash函数,都要加上处理冲突的方法。

187、分布式事务的原理,如何使用分布式事务?
分布式事务就是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上。简单的说,就是一次大的操作由不同的小操作组成,这些小的操作分布在不同的服务器上,且属于不同的应用,分布式事务需要保证这些小操作要么全部成功,要么全部失败。本质上来说,分布式事务就是为了保证不同数据库的数据一致性。

XA目前在商业数据库支持的比较理想,在mysql数据库中支持的不太理想。
所谓的消息事务就是基于消息中间件的两阶段提交,本质上是对消息中间件的一种特殊利用,它是将本地事务和发消息放在了一个分布式事务里,保证要么本地操作成功成功并且对外发消息成功,要么两者都失败。
在这里插入图片描述

分布式事务,本质上是对多个数据库的事务进行统一控制,按照控制力度可以分为:不控制、部分控制和完全控制。不控制就是不引入分布式事务,部分控制就是各种变种的两阶段提交,包括上面提到的消息事务+最终一致性、TCC模式,而完全控制就是完全实现两阶段提交。部分控制的好处是并发量和性能很好,缺点是数据一致性减弱了,完全控制则是牺牲了性能,保障了一致性,具体用哪种方式,最终还是取决于业务场景。作为技术人员,一定不能忘了技术是为业务服务的,不要为了技术而技术,针对不同业务进行技术选型也是一种很重要的能力!

188、linux怎么将一个目录下除了某个文件外的文件都删除
rm -rf !(file1|file2)

189、查询端口是否被占用
netstat -anp |grep 5000
看监控状态为LISTEN表示已经被占用,最后一列显示5000端口被服务python占用

190、删除表数据怎么最快?
truncate (table) tb 删除表中的所有数据,不能与where一起使用
delete from tb (where) 删除表中的数据
truncate和delete的区别
1、事务:truncate是不可以rollback的,但是delete是可以rollback的;
原因:truncate删除整表数据(ddl语句,隐式提交),delete是一行一行的删除,可以rollback
2、效果:truncate删除后将重新水平线和索引(id从零开始) ,delete不会删除索引
3、 truncate 不能触发任何Delete触发器。
4、delete 删除可以返回行数
效率上truncate比delete快,但truncate删除后不记录mysql日志,不可以恢复数据。
truncate相当于保留mysql表的结构,重新创建了这个表,所有的状态都相当于新表。

191、集线器、路由器、交换器分别属于哪一层?
第一层: 物理层 网线,集线器
第二层:数据链路层 网卡,交换机
第三层:网络层 路由器

192、编程创建一个500k的文件?
RandomAccessFile raf = null;
File filename = new File(“F:\psb.jpg”);
long length = 5;
try {
raf = new RandomAccessFile(filename, “rw”);
raf.setLength(length * 100000);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (raf != null) {
try {
raf.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

193、泛型和多态的含义?
泛型,即“参数化类型”,就是将类型由原来的具体的类型参数化。
多态是同一个行为具有多个不同表现形式或形态的能力

194、运行时异常和非运行时异常的区别及应用场景
运行时异常(RuntimeException)不需要编译器来检测。RuntimeException是所有可以在运行时抛出的异常的父类,需要手动捕捉异常。
受检查异常(checked exception)都是编译器在编译时进行校验的,通过throws语句或者try{}cathch{} 语句块来处理检测异常。编译器会分析哪些异常会在执行一个方法或者构造函数的时候抛出。

195、说明几种保证线程安全的方法
synchronized或lock

196、javaweb的分层方式及应用?
DAO层主要是做数据持久层的工作,负责与数据库进行联络的一些任务都封装在此,DAO层的设计首先是设计DAO的接口,然后在Spring的配置文件中定义此接口的实现类
Service层主要负责业务模块的逻辑应用设计,同样是首先设计接口,再设计其实现的类,接着再Spring的配置文件中配置其实现的关联。
Controller层负责具体的业务模块流程的控制,在此层里面要调用Serice层的接口来控制业务流程
View层:此层与控制层结合比较紧密,需要二者结合起来协同工作。View层主要负责前台jsp页面的表示。

mvc可以说是三层中的一个展现层框架,属于展现层。三层和mvc可以共存。 三层是基于业务逻辑来分的,而mvc是基于页面来分的。 MVC主要用于表现层,3层主要用于体系架构,3层一般是表现层、中间层、数据层,其中表现层又可以分成M、V、C,(Model View Controller)模型-视图-控制器 。

总的来说,也不能一概而论的说MVC和三层架构之间一点关系都没有,因为它们二者使用范围不同:三层可以应用于任何语言、任何技术的应用程序;而MVC只是为了解决B/S(Browser/Server)应用程序视图层各部分的耦合关系。它们互不冲突,可以同时存在,也可根据情况使用其中一种。

197、如何避免java内存泄漏
内存泄漏就是存在一些被分配的对象,这些对象有下面两个特点,首先,这些对象是可达的,即在有向图中,存在通路可以与其相连;其次,这些对象是无用的,即程序以后不会再使用这些对象。
1、尽早释放无用对象的引用 ,好的办法是使用临时变量的时候,让引用变量在推出活动域后自动设置为null;
2、避免集中创建对象,尤其是大对象,如果可以的话尽量使用流操作
3、不要在经常调用的方法中创建对象,尤其忌讳在循环中创建对象
4、尽量运用对象池技术以提高系统性能
5、避免使用finalize方法

198、如何利用Chrome工具进行前端js调试
1、在Chrome浏览器中运行你的web工程,打开“开发者模式”(右键选择检查或者按“F12“”)。打开你的sources选项,找到你所要调试的js文件。
2、在你想要调试的地方单击插入断点

199、Web开发常见安全问题及解决?
1.SQL注入
其本质是对于输入检查不充分,导致SQL语句将用户提交的非法数据当作语句的一部分来执行。解决方法使用SQL预处理方法prepareStatement
2.CSRF攻击(跨站点请求伪造)
伪造请求,冒充用户在站内的正常操作。
通过session token来实现保护。当客户端请求页面时,服务器会生成一个随机数Token,并且将Token放置到session当中,然后将Token发给客户端(一般通过构造hidden表单)。下次客户端提交请求时,Token会随着表单一起提交到服务器端。接收到请求后,服务器端会对Token值进行验证,判断是否和session中的Token值相等,若相等,则可以证明请求有效,不是伪造的。
3、XST处理
XST(跨站追踪)攻击,关闭Web 服务器的TRACE方法。
4、XSS攻击
XSS攻击是在HTML里代码执行了用户输入,解决方法是对数据进行转义处理。

200、Linux查看CPU和内存使用情况
top命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况,类似于Windows的任务管理器
top -u oracle
PID:进程的ID
  USER:进程所有者
  PR:进程的优先级别,越小越优先被执行
  NInice:值
  VIRT:进程占用的虚拟内存
  RES:进程占用的物理内存
  SHR:进程使用的共享内存
  S:进程的状态。S表示休眠,R表示正在运行,Z表示僵死状态,N表示该进程优先值为负数
  %CPU:进程占用CPU的使用率
  %MEM:进程使用的物理内存和总内存的百分比
  TIME+:该进程启动后占用的总的CPU时间,即占用CPU使用时间的累加值。
  COMMAND:进程启动命令名称

201、数据库结构设计考虑因素?
数据类型、索引、三大范式、冗余字段、应对大数据量

202、HDFS读写文件流程和读文件流程
写的详细流程:
① 客户端向HDFS写数据,首先跟namenode通信以确认可以写文件(namenode检查目标文件是否存在,父目录是否存在),确认可以上传,返回给客户端client
② client会先对文件进行切分,默认一个block块是128M,比如说,文件有300M,就会被切分成3块,两个128M,一个44M。然后client会向namenode请求上传第一个block
③ namenode返回datanode的服务器
④ client会请求一台datanode来上传数据(本质上是一个RPC 调用,建立pipeline).第一个datanode接收到请求会继续调用第二个datanode,然后第二个datanode会调用第三个datanode(多少个datanode跟配置的副本数有关),将整个pipeline建立完成,逐级返回给客户端
⑤ client开始往第一台datanode上上传第一个block(先从磁盘读取数据放到本地内存缓存中),以packet为单位(一个packet为64KB).当然在写入的时候datanode会进行数据校验,它并不是通过一个packet进行一次校验,而是以chunk为单位进行校验(512byte),第一台datanode收到一个packet就会传给第二台datanode,第二台再传给第三台。。。每一台每传一个packet会放入一个应答队列等待应答
⑥ 当一个block传输完成之后,client会再次请求namenode上传第二个block的datanode服务器。循环
在这里插入图片描述

读的详细流程:
① client向namenode请求下载文件,即向namenode通信查询元数据(block所在的datanode节点),找到文件块所在的datanode服务器
② client挑选一台datanode(就近原则,然后随机)服务器,请求建立socket流
③ datanode开始发送数据(从磁盘里面读取数据输入流,以packet为单位来做校验)
④ 客户端以packet为单位接收,先在本地缓存,然后写入目标文件,后面的block块就相当于是append到前面的block块最后合成最终需要的文件。
在这里插入图片描述
203、Spark的RDD五大特性
RDD,弹性分布式数据集,是spark的底层数据结构。
1 、A list of partitions
  --RDD是由多个partition构成的。
2、A function for computing each split
  --RDD的每个分区上都有一个函数去作用
3、 A list of dependencies on other RDDs
  --RDD有依赖性,通常情况下一个RDD是来源于另一个RDD,这个叫做lineage。RDD会记录下这些依赖,方便容错。
4、Optionally, a Partitioner for key-value RDDs (e.g. to say that the RDD is hash-partitioned)
  --可选项,如果RDD里面存的数据是key-value形式,则可以传递一个自定义的Partitioner进行重新分区,例如这里自定义的Partitioner是基于key进行分区,那则会将不同RDD里面的相同key的数据放到同一个partition里面。
5、Optionally, a list of preferred locations to compute each split on (e.g. block locations for an HDFS file)
最优的位置去计算,也就是数据的本地性。

204、linux下删除大量文件?
在linux中删除大量文件时,直接用rm会出现:-bash: /bin/rm: 参数列表过长的错误
find . -name “name*” | xargs rm -rf
假如文件名或文件夹名中包含空格:find . -name “name*” -print0 | xargs -0 rm -rf

205、将一个正整数分解为质因数

int n = 60;
		for (int i = 2; i <= n / 2; i++) {
			if (n % i == 0) {
				System.out.print(i + "*");
				n = n / i;
				i = 1;
			}
		}
		System.out.print(n);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

206、容器和虚拟机的区别及应用场景?
一个运用于应用程序,另一个是为操作系统设计的。
容器最大的优点之一是可以预留比虚拟机少的资源。请记住,容器本质上是单个应用程序,而虚拟机需要更多资源来运行整个操作系统。
容器对于快速的跨发行版部署是更可行的,而虚拟机对于像运行LAMP堆栈这样的单一应用程序使用情况是更好的。
与容器相比,虚拟机提供了更多的安全性。
容器可以共享系统资源而虚拟机不行。
容器用更少的硬件更高效地运行。在另一方面,虚拟机仍然是服务器和云空间的主要内容。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/708274
推荐阅读
相关标签
  

闽ICP备14008679号