面试总结
1 基础
为什么 Java 中只有值传递?
int 范围?float 范围?
2的31次方 float 8个指数位
hashCode 与 equals,什么关系?
如果两个对象相等,那么它们的hashCode()值一定相同。这里的相等是指,通过equals()比较两个对象时返回true
String StringBuffer 和 StringBuilder 的区别是什么?String 为什么是不可变的?
StringBuffer是线程安全,可以不需要额外的同步用于多线程中;
StringBuilder是非同步,运行于多线程中就需要使用着单独同步处理,但是速度就比StringBuffer快多了;
StringBuffer与StringBuilder两者共同之处:可以通过append、indert进行字符串的操作。
String:适用于少量的字符串操作的情况
StringBuilder:适用于单线程下在字符缓冲区进行大量操作的情况
StringBuffer:适用多线程下在字符缓冲区进行大量操作的情况
Java 序列化中如果有些字段不想进行序列化 怎么办?
构造器 Constructor 是否可被 override?
java 异常体系?RuntimeException Exception Error 的区别,举常见的例子
字符型常量和字符串常量的区别?
- 形式上: 字符常量是单引号引起的一个字符; 字符串常量是双引号引起的若干个字符
- 含义上: 字符常量相当于一个整型值( ASCII 值),可以参加表达式运算; 字符串常量代表一个地址值(该字符串在内存中存放位置)
- 占内存大小 字符常量只占2个字节; 字符串常量占若干个字节(至少一个字符结束标志) (注意: char在Java中占两个字节)
在调用子类构造方法之前会先调用父类没有参数的构造方法,其目的是?
为了实现对象的实例化.
- 子类中所有的构造函数都会默认调用父类中的无参构造函数, 因为每一个子类构造函数内第一行都有隐式的 super();
- 若父类中没有无参构造函数, 那么子类的构造函数内必须通过 super 语句指定要调用的父类中的构造函数.
- 若子类构造函数中用 this 来指定调用子类自己的构造函数, 那么被调用的构造函数也一样会调用父类中的构造函数.
2 集合
集合这块关注一下 1.8 的实现吧,和 1.7 相比变化了很多
ArrayList和linkedList的区别?
堆是怎么存储的,插入是在哪里?
HashMap和HashTable的区别?讲一下 hashMap 原理。hashMap 可以并发读么?并发写会有什么问题?
集合类存放于 Java.util 包中, 主要有几种接口?
.interface collection是最基本的集合接口。interface list,interface set,interface map是三种常见的集合类接口。所有的类都不能直接实现collection接口,而只能实现list,set,map接口。
Array与ArrayList有什么不一样?简单介绍下 ArrayList 怎么实现,加操作、取值操作,什么时候扩容? grow()方法扩容
①Array是Java中的数组,声明数组有三种方式
int[] a=new int[10];
int a[]=new int[10];
int a[]={1,2,3,4};
可以看出:在定义一个数组的时候,必须指定这个数组的数据类型及数组的大小,也就是说数组中存放的元素个数固定并且类型一样
②ArrayList是动态数组,也就是数组的复杂版本,它可以动态的添加和删除元素,被称为”集合“,集合的声明如下
ArrayList list = new ArrayList(10);
ArrayList list1 = new ArrayList();
//创建1个数组集合 ArrayList<String> array=new ArrayList<String>(); //添加元素 array.add("one"); array.add("two"); array.add("three"); System.out.println("array:"+array); //获取元素 System.out.println(array.get(0)); System.out.println(array.get(1)); System.out.println(array.get(2)); //数组集合的长度 System.out.println("数组集合的长度:"+array.size()); //删除元素 System.out.println("remove:"+array.remove("one")); System.out.println("array:"+array); System.out.println("remove:"+array.remove(1)); System.out.println("array:"+array); //修改元素 System.out.println(array.set(0,"柯南")); System.out.println("array:"+array);
说说ConcurrentHashMap?头插法还是尾插法?扩容怎么做?
分段锁(段内扩容,重新hash)
集合在迭代的过程中,插入或删除数据会怎样?
3 并发
notify()和notifyAll()有什么区别?
然后再来说notify和notifyAll的区别
如果线程调用了对象的 wait()方法,那么线程便会处于该对象的等待池中,等待池中的线程不会去竞争该对象的锁。
当有线程调用了对象的 notifyAll()方法(唤醒所有 wait 线程)或 notify()方法(只随机唤醒一个 wait 线程),被唤醒的的线程便会进入该对象的锁池中,锁池中的线程会去竞争该对象锁。也就是说,调用了notify后只要一个线程会由等待池进入锁池,而notifyAll会将该对象等待池内的所有线程移动到锁池中,等待锁竞争
优先级高的线程竞争到对象锁的概率大,假若某线程没有竞争到该对象锁,它还会留在锁池中,唯有线程再次调用 wait()方法,它才会重新回到等待池中。而竞争到对象锁的线程则继续往下执行,直到执行完了 synchronized 代码块,它会释放掉该对象锁,这时锁池中的线程会继续竞争该对象锁。
volatile 是什么?可以保证有序性吗?
主线程将vt.flag的值同样 从主内存中拷贝到自己的线程工作内存 然后修改flag=true. 然后再将新值回到主内存。
这就解释了为什么在主线程(main)中设置了vt.flag = true; 而vt线程在进行判断flag的时候拿到的仍然是false。那就是因为vt线程每次判断flag标记的时候是从它自己的“工作内存中”取值,而并非从主内存中取值!
这也是JVM为了提供性能而做的优化。那我们如何能让vt线程每次判断flag的时候都强制它去主内存中取值呢。这就是volatile关键字的作用。
volatile boolean flag = false;
为什么wait, notify 和 notifyAll这些方法不在thread类里面?
我想你的电脑里有一个叫cpu的长工,他很得力,不论你给他什么指令,他都竭尽所能的去做。但是长工cpu做事有讲究,不论做什么工作,你都要先一条一条的说清楚你要干啥,实际上就是一组指令序列,我们把他叫做线程,对cpu就是一个编排好的指令序列,你有很多工作都要让长工cpu做,所以你给他指定多个指令序列,就是多个线程A,B,C,D. 正常情况下cpu执行完了A线程的指令序列,再去执行B线程的,但是世界的奇妙之处在于指令序列中有些指令长工cpu也没法立刻执行,比如指令从队列中取整数并加一,因为cpu发现队列中还一个整数没有,长工cpu只能等在那里,等一个整数出现,他才能继续他的工作。但是这时老兄线程B不爽了,凭啥你线程A可以这样占着长工兄弟,却让他在那打酱油啥事不做却死等,这不符合我们资本主义一贯的996作风,于是线程们经过第一届论如何让cpu扎实的工作的讨论大会后,给出了如下的解决方案,给出一个协调者对象Object,他的主要工作是如何协调谁去使用长工cpu, 这是由它的三个api,分别是wait,notify,notifyall 给出的。
当线程A中包含一条依赖外部环境的情况来决定能否执行的指令时,它加一条对外界环境试探的指令,如果这个指令返回说现在的情况下一条指令不能执行,那么它就会调用协调者object对象的api wait,协调者就会告诉长工,先别在线程A这里干了,去看看线程B啊C啊有没有活干。
SynchronizedMap和ConcurrentHashMap有什么区别?
SynchronizedMap 一次锁住整张表来保证线程安全,所以每次只能有一个线程来
访为 map。
ConcurrentHashMap 使用分段锁来保证在多线程下的性能。
ConcurrentHashMap 中则是一次锁住一个桶。ConcurrentHashMap 默认将
hash 表分为 16 个桶,诸如 get,put,remove 等常用操作只锁当前需要用到的桶。
这样,原来只能一个线程进入,现在却能同时有 16 个写线程执行,并发性能的提
升是显而易见的。
另外 ConcurrentHashMap 使用了一种不同的迭代方式。在这种迭代方式中,当
iterator 被创建后集合再发生改变就不再是抛出
ConcurrentModificationException,取而代之的是在改变时 new 新的数据从而
不影响原有的数据 ,iterator 完成后再将头指针替换为新的数据 ,这样 iterator
线程可以使用原来老的数据,而写线程也可以并发的完成改变。
什么是线程安全?Vector是一个线程安全类吗?
查看源码得知,所谓安全,是在方法上加上了synchronized关键字以保证单线程持有。
但是,使用synchronized关键字做线程安全的话,效率低,且不可修改。因为synchronized关键字是JVM级别的,不可控,靠JVM内部机制进行关键字识别以及对象的持有和释放,因此,使用Vector的话,效率很慢。
而且,使用了synchronized关键字,是可以达到局域性线程同步,但是并不是真正的线程安全。因为:单个方法的原子性(注:原子性,程序的原子性即不会被线程调度机制打断),并不能保证复合操作也具有原子性。
即:复合操作有可能打破单方法的原子性。
if (!vector.contains(element)) vector.add(element); then do sm }
但作为 vector 之外的使用环境,仍然存在 race condition: 因为虽然条件判断 if (!vector.contains(element))与方法调用 vector.add(element); 都是原子性的操作 (atomic),但在 if 条件判断为真后,那个用来访问vector.contains 方法的锁已经释放,在即将的 vector.add 方法调用 之间有间隙,在多线程环境中,完全有可能被其他线程获得 vector的 lock 并改变其状态, 此时当前线程的vector.add(element); 正在等待。只有当其他线程释放了 vector 的 lock 后,vector.add(element); 继续,但此时它已经基于一个错误的假设了。
因此:
单个的方法 synchronized 了并不代表组合(compound)的方法调用具有原子性,使 compound actions 成为线程安全的可能解决办法之一还是离不开intrinsic lock (这个锁应该是 vector 的,但由 client 维护):
所以我们在使用的时候还要这样,在putIfAbsent的时候,先将vector对象进行加锁:
public static void main(String[] args) { Vector vector = new Vector(); vector.add("aaa"); vector.add("666"); putIfAbsent(vector,"666"); } public static void putIfAbsent(Vector vector,Object object) { synchronized(vector) { if (!vector.contains(object)) { vector.add(object); }else { System.out.println("The vertor is contains the object of "+object.toString()); } } } 结果输出: The vertor is contains the object of 666
结论:
Vector 和 ArrayList 实现了同一接口 List, 但所有的 Vector 的方法都具有 synchronized 关键修饰。但对于复合操作,Vector 仍然需要进行同步处理。
线程进程和线程的区别?并行和并发的区别?了解协程么?进程间如何通信:进程 A 想读取进程 B 的主存怎么办?线程间通信?线程的生命周期有哪些状态?怎么转换?wait 和 sleep 有什么区别?什么情况下会用到 sleep?怎么停止线程?怎么
都用来进行线程控制,他们最大本质的区别是:sleep()不释放同步锁,wait()释放同步缩.;
基本差别
sleep是Thread类的方法,wait是Object类中定义的方法
sleep()方法可以在任何地方使用
wait()方法只能在synchronized方法或synchronized块中使用
本质区别
Thread.sleep智慧让出CPU,不会导致锁行为的改变
Object.wait不仅让出CPU,还会释放已经占有的同步资源锁
控制多个线程按序执行?https://blog.csdn.net/weixin_43338519/article/details/107966496
方法一:使用join()方法让一个线程强制运行
方法二:使用juc包下的Executors线程池保证子线程按顺序执行
使用Executors中的newSingleThreadExecutor()方法,创建一个单线程的线程池,
将线程用排队的方式扔进一个线程池里,让所有的任务以单线程的模式,按照FIFO先进先出,也可以达到控制线程执行顺序的目的
方法三:用CountdownLach保证子线程按顺序执行
方法四:用BlockingQueue
说说自己是怎么使用 synchronized 关键字,在项目中用到了吗?synchronized关键字最主要的三种使用方式
为什么要用 join()方法?
主线程生成并起动了子线程,而子线程里要进行大量的耗时的运算(这里可以借鉴下线程的作用),当主线程处理完其他的事务后,需要用到子线程的处理结果,这个时候就要用到join()方法了。
什么是多线程中的上下文切换?
死锁与活锁的区别,死锁与饥饿的区别?
Java 中用到的线程调度算法是什么?
计算机通常只有一个 CPU,在任意时刻只能执行一条机器指令,每个线程只有获得
CPU 的使用权才能执行指令.所谓多线程的并发运行,其实是指从宏观上看,各个线
程轮流获得 CPU 的使用权,分别执行各自的任务.在运行池中,会有多个处于就绪状
态的线程在等待 CPU,JAVA 虚拟机的一项任务就是负责线程的调度,线程调度是指
按照特定机制为多个线程分配 CPU 的使用权.
有两种调度模型:分时调度模型和抢占式调度模型。
分时调度模型是指让所有的线程轮流获得 cpu 的使用权,并且平均分配每个线程占
用的 CPU 的时间片这个也比较好理解。
java 虚拟机采用抢占式调度模型,是指优先让可运行池中优先级高的线程占用
CPU,如果可运行池中的线程优先级相同,那么就随机选择一个线程,使其占用
CPU。处于运行状态的线程会一直运行,直至它不得不放弃 CPU。
什么是原子操作?在 Java Concurrency API 中有哪些原子类(atomic classes)?
原子操作(atomic operation)意为”不可被中断的一个或一系列操作” 。处理器使用基于对缓存加锁或总线加锁的方式来实现多处理器之间的原子操作。在Java中可以通过锁和循环CAS的方式来实现原子操作。CAS操作——Compare & Set,或是 Compare & Swap,现在几乎所有的CPU指令都支持CAS的原子操作。
原子操作是指一个不受其他操作影响的操作任务单元。原子操作是在多线程环境下避免数据不一致必须的手段。int++并不是一个原子操作,所以当一个线程读取它的值并加1时,另外一个线程有可能会读到之前的值,这就会引发错误。
为了解决这个问题,必须保证增加操作是原子的,在JDK1.5之前我们可以使用同步技术来做到这一点。到JDK1.5,java.util.concurrent.atomic包提供了int和long类型的原子包装类,它们可以自动的保证对于他们的操作是原子的并且不需要使用同步。
java.util.concurrent这个包里面提供了一组原子类。其基本的特性就是在多线程环境下,当有多个线程同时执行这些类的实例包含的方法时,具有排他性,即当某个线程进入方法,执行其中的指令时,不会被其他线程打断,而别的线程就像自旋锁一样,一直等到该方法执行完成,才由JVM从等待队列中选择一个另一个线程进入,这只是一种逻辑上的理解。
原子类:AtomicBoolean,AtomicInteger,AtomicLong,AtomicReference
原子数组:AtomicIntegerArray,AtomicLongArray,AtomicReferenceArray
原子属性更新器:AtomicLongFieldUpdater,AtomicIntegerFieldUpdater,AtomicReferenceFieldUpdater
什么是阻塞队列?阻塞队列的实现原理是什么?如何使用阻塞队列来实现生产者-消费者
模型?
阻塞队列(BlockingQueue)是一个支持两个附加操作的队列。
这两个附加的操作是:在队列为空时,获取元素的线程会等待队列变为非空。当队列满时,存储元素的线程会等待队列可用。
阻塞队列常用于生产者和消费者的场景,生产者是往队列里添加元素的线程,消费者是从队列里拿元素的线程。阻塞队列就是生产者存放元素的容器,而消费者也只从容器里拿元素。
JDK7提供了7个阻塞队列。分别是:
ArrayBlockingQueue :一个由数组结构组成的有界阻塞队列。
LinkedBlockingQueue :一个由链表结构组成的有界阻塞队列。
PriorityBlockingQueue :一个支持优先级排序的无界阻塞队列。
DelayQueue:一个使用优先级队列实现的无界阻塞队列。
SynchronousQueue:一个不存储元素的阻塞队列。
LinkedTransferQueue:一个由链表结构组成的无界阻塞队列。
LinkedBlockingDeque:一个由链表结构组成的双向阻塞队列。
Java 5之前实现同步存取时,可以使用普通的一个集合,然后在使用线程的协作和线程同步可以实现生产者,消费者模式,主要的技术就是用好,wait ,notify,notifyAll,sychronized这些关键字。而在java 5之后,可以使用阻塞队列来实现,此方式大大简少了代码量,使得多线程编程更加容易,安全方面也有保障。
BlockingQueue接口是Queue的子接口,它的主要用途并不是作为容器,而是作为线程同步的的工具,因此他具有一个很明显的特性,当生产者线程试图向BlockingQueue放入元素时,如果队列已满,则线程被阻塞,当消费者线程试图从中取出一个元素时,如果队列为空,则该线程会被阻塞,正是因为它所具有这个特性,所以在程序中多个线程交替向BlockingQueue中放入元素,取出元素,它可以很好的控制线程之间的通信。
阻塞队列使用最经典的场景就是socket客户端数据的读取和解析,读取数据的线程不断将数据放入队列,然后解析线程不断从队列取数据解析。
AQS了解 AQS 么?讲讲底层实现原理AQS 有那些实现?讲讲 AtomicInteger 的底层实现
AQS底层原理
概念
AQS是一个同步队列,全名为AbstractQueuedSynchronizer,它是一个同步工具,是Lock用来实现线程同步的核心组件。
AQS的功能分为两种:独占和共享
独占锁:每次只能有一个线程获取锁,比如ReentrantLock是以独占的方式实现互斥
共享锁:允许多个线程同时获取锁,并发的访问共享资源,比如ReentrantReadWriteLock
内部实现
AQS队列内部维护的是一个FIFO的双向链表。每个Node由线程封装,当线程争抢锁失败后会封装成Node加入
AQS队列中去。当获取锁的线程释放锁以后,会从队列中唤醒一个阻塞的节点
————————————————
版权声明:本文为CSDN博主「Starry*sky」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_40500437/article/details/109126825
为什么我们调用 start()方法时会执行 run()方法,为什么我们不能直接调用 run()方
法?
为什么我们调用start()方法时会执行run()方法?
因为类Thread中的start方法中,调用了Thread中的run方法。顺便说下,类A继承了Tread类,在A中写run方法,就会覆盖掉Thread中的run方法,所以此时调用start方法后,实现的是自己的run方法体里面的代码。
为什么我们不能直接调用run()方法?
如果我们直接调用子线程的run()方法,其方法还是运行在主线程中,代码在程序中是顺序执行的,所以不会有解决耗时操作的问题。所以不能直接调用线程的run()方法,只有子线程开始了,才会有异步的效果。当thread.start()方法执行了以后,子线程才会执行run()方法,这样的效果和在主线程中直接调用run()方法的效果是截然不同的。
start( )与run( )之间有什么区别?
run()方法:在本线程内调用该Runnable对象的run()方法,可以重复多次调用;
start()方法:启动一个线程,调用该Runnable对象的run()方法,不能多次启动一个线程;
————————————————
版权声明:本文为CSDN博主「猿梦在路上」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/dashuai410329/article/details/78522959
Java 中你怎样唤醒一个阻塞的线程?
wait() 和 notify() 方法
两个方法搭配使用,wait()使线程进入阻塞状态,调用notify()时,线程进入可执行状态。wait()内可加或不加参数,加参数时是以毫秒为单位,当到了指定时间或调用notify()方法时,进入可执行状态。(属于Object类,而不属于Thread类,wait()会先释放锁住的对象,然后再执行等待的动作。由于wait()所等待的对象必须先锁住,因此,它只能用在同步化程序段或者同步化方法内,否则,会抛出异常IllegalMonitorStateException.)
join()方法
也叫线程加入。是当前线程A调用另一个线程B的join()方法,当前线程转A入阻塞状态,直到线程B运行结束,线程A才由阻塞状态转为可执行状态。
什么是线程组,为什么在 Java 中不推荐使用?
ThreadGroup 类,可以把线程归属到某一个线程组中,线程组中可以有线程对象,
也可以有线程组,组中还可以有线程,这样的组织结构有点类似于树的形式。
为什么不推荐使用?因为使用有很多的安全隐患吧,没有具体追究,如果需要使
用,推荐使用线程池。
4 IO
IO 这块我不熟,没有多讲
了解 NIO 么?讲讲
NIO 与 BIO 有什么区别?
了解 Netty 原理么
JVM
1 内存与 GC
GC 是什么?为什么要有 GC?
jvm 内存区域分布?gc 发生在哪些部分?
发生在堆区。
栈区方法执行完就没了
你能保证 GC 执行吗?
怎么获取 Java 程序使用的内存?堆使用的百分比?
介绍一下垃圾回收过程。
垃圾回收算法的了解。现在用的什么回收算法? https://blog.csdn.net/yrwan95/article/details/82829186
1.Mark-Sweep(标记-清除)算法
2.Copying(复制)算法
3.Mark-Compact(标记-整理)算法(压缩法)
4.Generational Collection(分代收集)算法
什么时候会触发FullGC
1. System.gc()方法的调用
2、老年代空间不足
3、永生区空间不足
现在使用的什么垃圾回收器?知道哪些?讲讲 G1
容器的内存和 jvm 的内存有什么关系?参数怎么配置?
2 异常与调优
线上有什么 jvm 参数调整?
我们的应用中用的环境是apache2.0.26+jboss4.0.5+jdk1.6,jvm的环境变量设置如下:
-server -Xmx2g -Xms2g -Xmn256m -XX:PermSize=128m -Xss256k -XX:+DisableExplicitGC -XX:+UseConcMarkSweepGC -XX
:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:LargePageSizeInBytes=128m -XX:+UseFastAccessorMethods -XX:+UseCMSI
nitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70
-Xms2g JVM初始分配的内存由-Xms指定,默认是物理内存的1/64但小于1G。
-Xmx2g JVM最大分配的内存由-Xmx指定,默认是物理内存的1/4但小于1G。
-XX:PermSize=128m 装载Class信息等基础数据,默认64M
-Xss256k 设置每个线程的堆栈大小。JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K
-XX:DisableExplicitGC禁止调用代码System.gc()
-XX:+UseConcMarkSweepGC 指定在 Old Generation 使用 concurrent cmark sweep gc,gc thread 和 app thread 并行 ( 在 init-mark 和 remark 时 pause app thread). app pause 时间较短 , 适合交互性强的系统 , 如 web server
-XX:+CMSParallelRemarkEnabled 在使用 UseParNewGC 的情况下 , 尽量减少 mark 的时间
XX:+UseCMSCompactAtFullCollection 在使用 concurrent gc 的情况下 , 防止 memory fragmention, 对 live object 进行整理 , 使 memory 碎片减少
-XX:LargePageSizeInBytes=128m 指定 Java heap 的分页页面大小 , 如 :-XX:LargePageSizeInBytes=128m
-XX:+UseFastAccessorMethods get,set 方法转成本地代码
-XX:+UseCMSInitiatingOccupancyOnly 指示只有在 old generation 在使用了初始化的比例后 concurrent collector 启动收集
XX:CMSInitiatingOccupancyFraction=70 指示在 old generation 在使用了 n% 的比例后 , 启动 concurrent collector, 默认值是 68, 如 :-XX:CMSInitiatingOccupancyFraction=70
————————————————
版权声明:本文为CSDN博主「zhongweij」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/zhongweij/article/details/83778723
oom 问题排查思路
线上问题排查,突然长时间未响应,怎么排查,oom
cpu 使用率特别高,怎么排查?通用方法?定位代码?cpu高的原因?
频繁 GC 原因?什么时候触发 FGC?
怎么获取 dump 文件?怎么分析?
3 类加载器
怎么实现自己的类加载器?
3.1 明确类加载器功能
- 获取class文件的二进制字节流
- 将这些字节流写入内存
3.2 获取字节流
这个相对简单点,有点I/O知识就行,下面是我从网上复制别人的代码
类加载过程?
初始化顺序?
Spring
不同版本的 Spring Framework 有哪些主要功能?
讲一下 ioc、aop
ioc 怎么防止循环依赖
前面说到对象的创建,那么在创建的过程中Spring是怎么又是如何解决循环依赖的呢。前面提到有个三级缓存。就是利用这个来解决循环依赖。打个比方说实例化A的时候,先将A创建(早期对象)放入一个池子中。这个时候虽然属性没有赋值,但是容器已经能认识这个是A对象,只是属性全是null而已。
aop 的实现原理、动态代理过程
区分 BeanFactory 和 ApplicationContext?
spring bean 容器的生命周期是什么样的?
1、Spring 容器根据配置中的 bean 定义中实例化 bean。
2、Spring 使用依赖注入填充所有属性,如 bean 中所定义的配置。
3、如果 bean 实现BeanNameAware 接口,则工厂通过传递 bean 的 ID 来调用setBeanName()。
4、如果 bean 实现 BeanFactoryAware 接口,工厂通过传递自身的实例来调用 setBeanFactory()。
5、如果存在与 bean 关联的任何BeanPostProcessors,则调用 preProcessBeforeInitialization() 方法。
6、如果为 bean 指定了 init 方法( <bean> 的 init-method 属性),那么将调用它。
7、最后,如果存在与 bean 关联的任何 BeanPostProcessors,则将调用 postProcessAfterInitialization() 方法。
8、如果 bean 实现DisposableBean 接口,当 spring 容器关闭时,会调用 destory()。
9、如果为bean 指定了 destroy 方法( <bean> 的 destroy-method 属性),那么将调用它。
@Autowired 注解有什么用?
@Autowired 的作用是什么?
@Autowired 是一个注释,它可以对类成员变量、方法及构造函数进行标注,让 spring 完成 bean 自动装配的工作。
@Autowired 默认是按照类去匹配,配合 @Qualifier 指定按照名称去装配 bean。
使用 Spring 访问 Hibernate 的方法有哪些?
Spring 处理请求的过程?
Redis
为什么要用 redis /为什么要用缓存(高性能、高并发)
redis 常见数据结构以及使用场景分析(String、Hash、List、Set、Sorted Set)
Redis 常见异常及解决方案(缓存穿透、缓存雪崩、缓存预热、缓存降级)
分布式环境下常见的应用场景(分布式锁、分布式自增 ID)
Redis集群方案应该怎么做?都有哪些方案?
Redis 集群的主从复制模型是怎样的?
redis 持久化机制(怎么保证 redis 挂掉之后再重启数据可以进行恢复)
如何解决 Redis 的并发竞争 Key 问题?
如何保证缓存与数据库双写时的数据一致性?
redis 的 zset 的使用场景?底层实现?为什么要用跳表?
MySQL
事务的并发?事务隔离级别,每个级别会引发什么问题,MySQL默认是哪个级别?
下面简单地介绍一下四种隔离级别。
READ UNCOMMITTED (未提交读)
在READ UNCOMMITTED级别,事务中的修改,即使没有提交,对其他事务也都是可见的。事务可以读取未提交的数据,这也被称为脏读( Dirty Read )。
这个级别会导致很多问题,从性能上来说,READ UNCOMMITTED不会比其他的级别好太多,
但却缺乏其他级别的很多好处,除非真的有非常必要的理由,在实际应用中一般很少使用。
READ COMMITTED(提交读)
大多数数据库系统的默认隔离级别都是 READ COMMITTED(但 MysQL 不是)。
READ COMMITTED 满足前面提到的隔离性的简单定义:一个事务开始时,只能“看见”已经提交的事务所做的修改。
换句话说,
一个事务从开始直到提交之前,所做的任何修改对其他事务都是不可见的。
这个级别有时候也叫做不可重复读(nonrepeatable read) ,因为两次执行同样的查询,可能会得到不一样的结果。
REPEATABLE READ(可重复读)
REPEATABLE READ 解决了脏读的问题。该级别保证了在同一个事务中多次读取同样记录的结果是一致的。
但是理论上,可重复读隔离级别还是无法解决另外一个幻读 ( Phantom Read )的问题。
所谓幻读,指的是当某个事务在读取某个范围内的记录时,另外一个事务又在该范围内插入了新的记录,
当之前的事务再次读取该范围的记录时,会产生幻行( Phantom Row )。
InnoDB 和 XtraDB 存储引攀通过多版本并发控制( Mvcc , Multiversion Concurrency Control )解决了幻读的问题。
本章稍后会做进一步的讨论。
可重复读是 MySQL 的默认事务隔离级别。
SERIALIZABLE (可串行化)
SERIALIZABLE 是最高的隔离级别。它通过强制事务串行执行,避免了前面说的幻读的问题。
简单来说, SERIALIZABLE 会在读取的每一行数据上都加锁,所以可能导致大量的超时和锁争用的问题。
实际应用中也很少用到这个隔离级别.只有在非常需要确保数据的一致性而且可以接受没有并发的情况下,才考虑采用该级别。
MySQL的MyISAM与InnoDB两种存储引擎在,事务、锁级别,各自的适用场景?
有哪些锁(乐观锁悲观锁),select 时怎么加排它锁?
乐观锁
乐观锁不是数据库自带的,需要我们自己去实现。乐观锁是指操作数据库时(更新操作),想法很乐观,认为这次的操作不会导致冲突,在操作数据时,并不进行任何其他的特殊处理(也就是不加锁),而在进行更新后,再去判断是否有冲突了。
通常实现是这样的:在表中的数据进行操作时(更新),先给数据表加一个版本(version)字段,每操作一次,将那条记录的版本号加1。也就是先查询出那条记录,获取出version字段,如果要对那条记录进行操作(更新),则先判断此刻version的值是否与刚刚查询出来时的version的值相等,如果相等,则说明这段期间,没有其他程序对其进行操作,则可以执行更新,将version字段的值加1;如果更新时发现此刻的version值与刚刚获取出来的version的值不相等,则说明这段期间已经有其他程序对其进行操作了,则不进行更新操作。
举例:
下单操作包括3步骤:
1.查询出商品信息
select (status,status,version) from t_goods where id=#{id}
2.根据商品信息生成订单
3.修改商品status为2
update t_goods
set status=2,version=version+1
where id=#{id} and version=#{version};
除了自己手动实现乐观锁之外,现在网上许多框架已经封装好了乐观锁的实现,如hibernate,需要时,可能自行搜索"hiberate 乐观锁"试试看。
悲观锁
与乐观锁相对应的就是悲观锁了。悲观锁就是在操作数据时,认为此操作会出现数据冲突,所以在进行每次操作时都要通过获取锁才能进行对相同数据的操作,这点跟java中的synchronized很相似,所以悲观锁需要耗费较多的时间。另外与乐观锁相对应的,悲观锁是由数据库自己实现了的,要用的时候,我们直接调用数据库的相关语句就可以了。
说到这里,由悲观锁涉及到的另外两个锁概念就出来了,它们就是共享锁与排它锁。共享锁和排它锁是悲观锁的不同的实现,它俩都属于悲观锁的范畴。
共享锁
共享锁指的就是对于多个不同的事务,对同一个资源共享同一个锁。相当于对于同一把门,它拥有多个钥匙一样。就像这样,你家有一个大门,大门的钥匙有好几把,你有一把,你女朋友有一把,你们都可能通过这把钥匙进入你们家,进去啪啪啪啥的,一下理解了哈,没错,这个就是所谓的共享锁。
刚刚说了,对于悲观锁,一般数据库已经实现了,共享锁也属于悲观锁的一种,那么共享锁在mysql中是通过什么命令来调用呢。通过查询资料,了解到通过在执行语句后面加上 lock in share mode就代表对某些资源加上共享锁了。
比如,我这里通过mysql打开两个查询编辑器,在其中开启一个事务,并不执行commit语句
city表DDL如下:
CREATE TABLE `city` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`state` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=utf8;
begin;
SELECT * from city where id = "1" lock in share mode;
然后在另一个查询窗口中,对id为1的数据进行更新
update city set name="666" where id ="1";
此时,操作界面进入了卡顿状态,过几秒后,也提示错误信息
[SQL]update city set name="666" where id ="1";
[Err] 1205 - Lock wait timeout exceeded; try restarting transaction
那么证明,对于id=1的记录加锁成功了,在上一条记录还没有commit之前,这条id=1的记录被锁住了,只有在上一个事务释放掉锁后才能进行操作,或用共享锁才能对此数据进行操作。
————————————————
版权声明:本文为CSDN博主「水中加点糖」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/puhaiyang/article/details/72284702
排它锁
排它锁与共享锁相对应,就是指对于多个不同的事务,对同一个资源只能有一把锁。
与共享锁类型,在需要执行的语句后面加上 for update就可以了
行锁
行锁,由字面意思理解,就是给某一行加上锁,也就是一条记录加上锁。
比如之前演示的共享锁语句
SELECT * from city where id = "1" lock in share mode;
由于对于city表中,id字段为主键,就也相当于索引。执行加锁时,会将id这个索引为1的记录加上锁,那么这个锁就是行锁。
————————————————
版权声明:本文为CSDN博主「水中加点糖」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/puhaiyang/article/details/72284702
sql查询语句确定创建哪种类型的索引?如何优化查询?
什么是临时表,临时表什么时候删除?
mysql 脏页?
分库分表有哪些策略?怎么保证 id 唯一?
非关系型数据库和关系型数据库区别,优势比较?
数据库的读写分离、主从复制,主从复制分析的 7 个问题?
MySQL都有什么锁,死锁判定原理和具体场景,死锁怎么解决?
数据库崩溃时事务的恢复机制(REDO日志和UNDO日志)?
Undo Log是为了实现事务的原子性,在MySQL数据库InnoDB存储引擎中,还用了Undo Log来实现多版本并发控制(简称:MVCC)。
对 uuid 的理解?知道哪些 GUID、Random 算法?
主键选随机 id、uuid 还是自增 id?为什么?主键有序无序对数据库的影响?
主从复制的过程?复制原理?怎么保证强一致性?
Kafka
生产者和消费者的命令行是什么?
Kafka 怎么保证数据可靠性?
讲讲 kafka 维护消费状态跟踪的方法
为什么需要消息系统,mysql 不能满足需求吗?
Kafka 判断一个节点是否还活着有那两个条件?
Kafka 与传统 MQ 消息系统之间有三个关键区别?
kafka 分布式(不是单机)的情况下,如何保证消息的顺序消费?
kafka 如何不消费重复数据?比如扣款,我们不能重复的扣
网络
tcptcp 有哪些机制确保可靠性?拥塞控制怎么实现?close_wait 太多怎么处理?为什么会出现这种情况?
讲讲三次握手,四次挥手?
假设Client端发起中断连接请求,也就是发送FIN报文。Server端接到FIN报文后,意思是说"我Client端没有数据要发给你了",但是如果你还有数据没有发送完成,则不必急着关闭Socket,可以继续发送数据。所以你先发送ACK,"告诉Client端,你的请求我收到了,但是我还没准备好,请继续你等我的消息"。这个时候Client端就进入FIN_WAIT状态,继续等待Server端的FIN报文。当Server端确定数据已发送完成,则向Client端发送FIN报文,"告诉Client端,好了,我这边数据发完了,准备好关闭连接了"。Client端收到FIN报文后,"就知道可以关闭连接了,但是他还是不相信网络,怕Server端不知道要关闭,所以发送ACK后进入TIME_WAIT状态,如果Server端没有收到ACK则可以重传。“,Server端收到ACK后,"就知道可以断开连接了"。Client端等待了2MSL后依然没有收到回复,则证明Server端已正常关闭,那好,我Client端也可以关闭连接了。Ok,TCP连接就这样关闭了!
————————————————
版权声明:本文为CSDN博主「whuslei」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/whuslei/article/details/6667471
keepalive 有什么用?Https 原理?知道哪些 http 状态码有哪些?http 有哪些请求方法?put、post 实现上有什么区别?
前后端分离与不分离的区别?各有什么优缺点?
常见 web 攻击有哪些?了解 csrf 攻击么?
nginx 达到上限了怎么办?怎么对 nginx 负载均衡?dns?
nginx 负载均衡有哪些算法?各自有什么优缺点?
restful 的作用?有哪些优点和缺点?
什么是 cdn?header 中涉及到缓存的字段有哪些?cookie session 介绍一下html 页面,怎么与后端交互?流程是什么?涉及到哪些组件?http 协议,报文格式?
设计模式
什么是设计模式?你是否在你的代码里面使用过?
Java 中什么叫单例设计模式?请用 Java 写出线程安全的单例模式
在 Java 中,什么叫观察者设计模式?
举一个用 Java 实现的装饰模式(decorator design pattern) ?它是作用于对象层次还是类层次?
单例对于单例,你知道哪些实现方法?实现一个懒加载单例双重校验锁为什么需要双重校验?
使用工厂模式最主要的好处是什么?在哪里使用?
分布式
有哪些分布式组件是你最熟悉的,简单聊一聊。
cap 是指什么?mysql 满足 cap 中哪些?
分布式锁有哪些方式可以实现?各有什么优缺点?
什么是一致性 hash?自己实现一致性 hash,会用什么数据结构?
微服务
微服务架构有哪些优势?
单片,SOA 和微服务架构有什么区别?
什么是 RPC?怎么实现幂等性?
什么是 REST / RESTful 以及它的用途是什么?
配置中心有哪些选项?apollo 的架构?怎么无感实现已加载数据更新?
讲一下熔断概念?熔断原理?令牌桶?熔断三个状态关系?
熔断会影响性能么?有遇到过线上发生熔断么?不加会怎样?
算法题
基本都会问时间复杂度
有哪些常用排序算法?
手写快排,快排时间复杂度是多少?
快排算法是不是稳定的?什么是稳定性?
给定一个字母组成的字符串,找出不含有重复字符的最长子串的长度。
9 个硬币中有一个劣币,用天平秤,最坏几次?
深度优先,广度优先
括号匹配,时间复杂度,空间复杂度
单向链表的归并排序
1g 大小文件,里面每行是最大 16k 的单词,限制内存 1m,统计单词频率最多的 100 个单词
手写 100 位带小数的大数字的减法
你有什么想问的?+Offer 选择?
部门定位?岗位职责?目前在做什么业务?薪酬福利介绍?
目前手头的 offer 情况?这些公司你自己有什么倾向性呢?最看重什么因素?想加入一个怎么样的团队?
你的预期薪酬是多少?目前的薪资情况?
最近一年的绩效情况?
补充一下我2020下半年的offer情况,其实是拿到了美团架构、快手主 app、猿辅导斑马、腾讯 csig 等意向书的。而且我觉得面试前的““练手””十分重要,像我前期“裸面”就硬生生的浪费了阿里、蚂蚁、字节、Shopee 等的面试机会。所以,在这里我给大家伙的建议就是一定要做好充足的准备,不然也是耽搁面试官和自己的时间,并且面试的时候也会手足无措,毕竟肚子里没有货啊!
最后再三思考,还是选择了快手,准备下周一入职了!大家加油,跳槽面试无时不在,若是还没准备好,我建议等过完年去参加春招提前批也不错,但是这段空余的时间你可不能浪费,好好把握!
说到这儿了,最后在出来放一波福利吧!希望可以帮助到大家!
————————————————
版权声明:本文为CSDN博主「JavaBUGa」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/JavaBUGa/article/details/113885112