面试题常见考点

java的优点 、Java三大特性 、Java是多继承吗?如何实现多继承?

Java最基础的类是什么?这个类有什么方法? Object提供什么方法?

访问权限修饰符有哪些? protected哪些可以访问

抽象类接口区别 Final.finally.finanize区别 、final域修饰字段能保证线程安全?为什么? 你这个情况是不安全的,final修饰对象只这个对象的引用地址不能再变,但对象里的属性值是可以重新调set方法改变的。final修饰常量才表示的是这个常量值不能变化

Int integer区别以及等于10等于1000返回值 、 int和Integer的区别,拆箱与装箱发生在什么时期

怎么判断两个对象相等 、Equals和==区别 、是否重写过equals方法

java 接口和抽象类、为什么java要有抽象类和接口这两种?抽象类和接口的区别。

对于面向对象编程来说,抽象是它的一大特征之一。在Java中,可以通过两种形式来体现OOP的抽象:接口和抽象类。这两者有太多相似的地方,又有太多不同的地方。很多人在初学的时候会以为它们可以随意互换使用,但是实际则不然。今天我们就一起来学习一下Java中的接口和抽象类。下面是本文的目录大纲: 一.抽象类 二.接口 三.抽象类和接口的区别 若有不正之处,请多多谅解并欢迎批评指正,不甚感激。 一.抽象类 在了解抽象类之前,先来了解一下抽象方法。抽象方法是一种特殊的方法:它只有声明,而没有具体的实现。抽象方法的声明格式为:

abstract void fun();

抽象方法必须用abstract关键字进行修饰。如果一个类含有抽象方法,则称这个类为抽象类,抽象类必须在类前用abstract关键字修饰。因为抽象类中含有无具体实现的方法,所以不能用抽象类创建对象。 下面要注意一个问题:在《Java编程思想》一书中,将抽象类定义为“包含抽象方法的类”,但是后面发现如果一个类不包含抽象方法,只是用abstract修饰的话也是抽象类。也就是说抽象类不一定必须含有抽象方法。个人觉得这个属于钻牛角尖的问题吧,因为如果一个抽象类不包含任何抽象方法,为何还要设计为抽象类?所以暂且记住这个概念吧,不必去深究为什么。

[public] abstract class ClassName { abstract void fun();}

从这里可以看出,抽象类就是为了继承而存在的,如果你定义了一个抽象类,却不去继承它,那么等于白白创建了这个抽象类,因为你不能用它来做任何事情。对于一个父类,如果它的某个方法在父类中实现出来没有任何意义,必须根据子类的实际需求来进行不同的实现,那么就可以将这个方法声明为abstract方法,此时这个类也就成为abstract类了。 包含抽象方法的类称为抽象类,但并不意味着抽象类中只能有抽象方法,它和普通类一样,同样可以拥有成员变量和普通的成员方法。注意,抽象类和普通类的主要有三点区别: 1)抽象方法必须为public或者protected(因为如果为private,则不能被子类继承,子类便无法实现该方法),缺省情况下默认为public。 2)抽象类不能用来创建对象; 3)如果一个类继承于一个抽象类,则子类必须实现父类的抽象方法。如果子类没有实现父类的抽象方法,则必须将子类也定义为为abstract类。 在其他方面,抽象类和普通的类并没有区别。 二.接口 接口,英文称作interface,在软件工程中,接口泛指供别人调用的方法或者函数。从这里,我们可以体会到Java语言设计者的初衷,它是对行为的抽象。在Java中,定一个接口的形式如下:

[public] interface InterfaceName { }

接口中可以含有 变量和方法。但是要注意,接口中的变量会被隐式地指定为public static final变量(并且只能是public static final变量,用private修饰会报编译错误),而方法会被隐式地指定为public abstract方法且只能是public abstract方法(用其他关键字,比如private、protected、static、 final等修饰会报编译错误),并且接口中所有的方法不能有具体的实现,也就是说,接口中的方法必须都是抽象方法。从这里可以隐约看出接口和抽象类的区别,接口是一种极度抽象的类型,它比抽象类更加“抽象”,并且一般情况下不在接口中定义变量。 要让一个类遵循某组特地的接口需要使用implements关键字,具体格式如下:

class ClassName implements Interface1,Interface2,[....]{}

可以看出,允许一个类遵循多个特定的接口。如果一个非抽象类遵循了某个接口,就必须实现该接口中的所有方法。对于遵循某个接口的抽象类,可以不实现该接口中的抽象方法。 三.抽象类和接口的区别 1.语法层面上的区别 1)抽象类可以提供成员方法的实现细节,而接口中只能存在public abstract 方法; 2)抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是public static final类型的; 3)接口中不能含有静态代码块以及静态方法,而抽象类可以有静态代码块和静态方法; 4)一个类只能继承一个抽象类,而一个类却可以实现多个接口。 2.设计层面上的区别 1)抽象类是对一种事物的抽象,即对类抽象,而接口是对行为的抽象。抽象类是对整个类整体进行抽象,包括属性、行为,但是接口却是对类局部(行为)进行抽象。举个简单的例子,飞机和鸟是不同类的事物,但是它们都有一个共性,就是都会飞。那么在设计的时候,可以将飞机设计为一个类Airplane,将鸟设计为一个类Bird,但是不能将 飞行 这个特性也设计为类,因此它只是一个行为特性,并不是对一类事物的抽象描述。此时可以将 飞行 设计为一个接口Fly,包含方法fly( ),然后Airplane和Bird分别根据自己的需要实现Fly这个接口。然后至于有不同种类的飞机,比如战斗机、民用飞机等直接继承Airplane即可,对于鸟也是类似的,不同种类的鸟直接继承Bird类即可。从这里可以看出,继承是一个 “是不是”的关系,而 接口 实现则是 “有没有”的关系。如果一个类继承了某个抽象类,则子类必定是抽象类的种类,而接口实现则是有没有、具备不具备的关系,比如鸟是否能飞(或者是否具备飞行这个特点),能飞行则可以实现这个接口,不能飞行就不实现这个接口。 2)设计层面不同,抽象类作为很多子类的父类,它是一种模板式设计。而接口是一种行为规范,它是一种辐射式设计。什么是模板式设计?最简单例子,大家都用过ppt里面的模板,如果用模板A设计了ppt B和ppt C,ppt B和ppt C公共的部分就是模板A了,如果它们的公共部分需要改动,则只需要改动模板A就可以了,不需要重新对ppt B和ppt C进行改动。而辐射式设计,比如某个电梯都装了某种报警器,一旦要更新报警器,就必须全部更新。也就是说对于抽象类,如果需要添加新的方法,可以直接在抽象类中添加具体的实现,子类可以不进行变更;而对于接口则不行,如果接口进行了变更,则所有实现这个接口的类都必须进行相应的改动。 下面看一个网上流传最广泛的例子:门和警报的例子:门都有open( )和close( )两个动作,此时我们可以定义通过抽象类和接口来定义这个抽象概念:

abstract class Door { public abstract void open(); public abstract void close();}

或者:

interface Door { public abstract void open(); public abstract void close();}

但是现在如果我们需要门具有报警alarm( )的功能,那么该如何实现?下面提供两种思路: 1)将这三个功能都放在抽象类里面,但是这样一来所有继承于这个抽象类的子类都具备了报警功能,但是有的门并不一定具备报警功能; 2)将这三个功能都放在接口里面,需要用到报警功能的类就需要实现这个接口中的open( )和close( ),也许这个类根本就不具备open( )和close( )这两个功能,比如火灾报警器。 从这里可以看出, Door的open() 、close()和alarm()根本就属于两个不同范畴内的行为,open()和close()属于门本身固有的行为特性,而alarm()属于延伸的附加行为。因此最好的解决办法是单独将报警设计为一个接口,包含alarm()行为,Door设计为单独的一个抽象类,包含open和close两种行为。再设计一个报警门继承Door类和实现Alarm接口。

interface Alram { void alarm();} abstract class Door { void open(); void close();} class AlarmDoor extends Door implements Alarm { void oepn() { //.... } void close() { //.... } void alarm() { //.... }}

String stringbuffer stringbuilder 区别 、 string可否继承,为什么不能继承,为什么这么设计,final修饰的作用。String,Stringbuffer,StringBuilder的区别,为什么被final修饰就不能被继承。 String类的intern方法的作用?字符串常量池在什么位置?String类讲了一下。new一个类会创建几个对象之类的。常量池在1.8之后放哪?

Try catch finally里面的return谁先执行

集合都有哪些接口,哪些类 、用过哪些集合类、集合框架有哪些、java集合类有哪些

容器vector、list、map、set

java的集合类,ArrayList安全版本是怎么实现的、 可以怎么加锁、arraylist的底层实现,对比set,linkedlist的优势,如果需要线程安全,采用什么。ArrayList与LinkedList的区别 、ArrayList插入无序数后如何排序

hashmap结构,线程安全吗,put方法的考察 、HashMap 的实现 、Hashmap在 1.8以前怎么解决冲突的 、HashMap怎么遍历,遍历的同时remove掉元素可以吗?

Hashmap底层 、hashmap得结构、HashMap:如何解决Hash冲突,原理等等、HashMap、ConcurrentMap在jdk1.7和1.8的区别,分段锁和CAS/synchronized 、hashmap的原理,hash冲突怎么解决,为什么默认初始容量为2的指数。HashMap底层结构,插入操作,扩容操作,为什么要扩充2倍长度 、Hashmap如何实现线程安全,concurrentHashmap原理 、hashMap的扩容机制?(2倍扩容)为什么是2倍扩容 、JDK1.7中HashMap使用的头插法还是尾插法,解释一下原因;Hashmap底层 、Hashmap为什么用红黑树,为什么链地址法可以避免冲突 、Hashmap.

用hashmap实现一张表的数据存储,key是teacher的id,value是班级。如果要判断两个teacher的id是否相同用什么方法?只需要重写hashcode方法

在hash冲突比较严重的情况下,使用拉链法解决冲突。这是如果两个key相同的对象要存入hashmap,请问会发生什么情况?答发生value值的覆盖

集合类有哪些是线程安全的(vector和hashtable) vector是怎么实现线程安全的 红黑树查找的时间复杂度 红黑树和二叉树的区别 、哪些线程安全的集合类,介绍一下

集合工具类(Collections)用过吗?用过哪些方法?打乱是哪个方法(PS:没用过不知道这个方法????)

HashMap和TreeMap区别? TreeMap底层是什么?(红黑树还是二叉树?)

HashSet和TreeSet :新建一个 TreeMap 作为实际存储 Set 元素的容器。TreeMap 的实现就是红黑树数据结构,也就说是一棵自平衡的排序二叉树,这样就可以保证当需要快速检索指定节点。

说出你知道的解决哈希冲突的所有方法,hashmap为什么用链地址法,链表>=8时转成红黑树,为什么用红黑树?那又小于8以后会变成链表吗?如果在6,7,8来回变会怎么样? HashMap中解决Hash冲突的方式有哪些(1.7使用拉链法,1.8使用红黑树);

JDK1.8中HashMap相比于JDK1.7有什么改进(避免循环死锁);

数据的长度是有限的,但我们可能会往数组里面添加很多数据进去,数组总有被填满的时候,那样开发地址法也不管用了,当然,实际业务中,如果可以预料数据的大小,我们可以采用这样的方式解决部分问题,但问题是这样确实不是万无一失的解决办法,

更合适的方式是什么呢?其实就是hashMap中使用较多的链地址法,也就是一开始我们图中展示的,基本结构仍然是一个数组,但是数组的每个单元维护的不再是一个个数据,而是一个个链表,也就是类似于linkedList这样的结构,当新插入的多个数据通过计算hash函数得到的是相同的数组下标时候,我们只需要把值往这个索引位置维护的链表中插入即可

hashtable解决冲突的方法 、hash冲突的解决方式;Hashtable和Cocurrenthashmap区别 、HashMap和HashTable有什么区别 、HashTable与CocurrentHashMap的有什么区别

CHM, currentHashMap得实现原理 、concurrenthashmap的原理,如何加锁,怎么获得他的size()。ConcurrentHashMap 的实现 、ConcurrentHashMap的实现以及与HashTable的区别

HashMap跟ConcurrenHashMap机制,如何保证并发的。

list的线程安全集合知道哪些?CopyOnwriteAarryList说一下。 CopyOnWriteArrayList的底层以及与vector的区别

初始化去怎么做的

1.8后,cas以及synchronized在ConcurrentHashMap中用到了哪些地方、cas用到了哪些地方、什么什么原子操作方法用过没

java重载讲一下

static关键字、final 关键字 、static关键字 、static从加载到使用, static int a = 10;会直接初始化为10吗

array和list的优缺点,使用场景

jdbc的反射

如果我们在程序运行的时候得到一个字符串,而这个字符串是某个类的类名,要实例化这个类就需要用到反射。通过反射com.mysql.jdbc.Driver类,实例化该类的时候会执行该类内部的静态代码块,该代码块会在Java实现的DriverManager类中注册自己,DriverManager管理所有已经注册的驱动类,当调用DriverManager.geConnection方法时会遍历这些驱动类,并尝试去连接数据库,只要有一个能连接成功,就返回Connection对象,否则则报异常。

异常怎么处理的、error和exception的区别

Java8接口default方法的意义(脑袋嗡嗡的)

JDK8的一些新特性在项目中有用到吗

日常中遇到过什么异常或者错误

#

用过什么设计模式,了解单例模式吗(没怎么用过,但是知道一些,没再问) 、设计模式,观察者模式 、用过什么设计模式、介绍设计模式,随便说一种 、JDK哪里用到享元模式、那里用到原型模式、单例模式

手写单模式,写了懒汉式和双重检验,问了双双重检验为什么要这么写,为什么锁住了还要加null判断 。防止在加锁的时候另一个线程刚好创建了一个实例

git命令

git常用命令?tag标签?分支

讲一讲红黑树的特点

介绍链表、平衡二叉树、红黑树的时间复杂度。链表的时间复杂度对插入,修改为O(1),查询为O(N),平衡二叉树为O(logN),红黑树我就介绍了下概念,

说是特殊的二叉排序树,以及根节点,叶子结点粉笔是什么颜色的结点以及规则。时间复杂度说不太了解使用的少。

红黑树原理?跟二叉树的区别?

1.Nio,AIO,BIO

讲一下java的线程安全

线程安全就是多线程访问时,采用了加锁机制,当一个线程访问该类的某个数据时,进行保护,其他线程不能进行访问直到该线程读取完,其他线程才可使用。不会出现数据不一致或者数据污染。

线程不安全就是不提供数据访问保护,有可能出现多个线程先后更改数据造成所得到的数据是脏数据

线程

并发,为什么要用多线程?多线程的好处?最大化利用CPU和CPU时间片

介绍多线程

JAVA中的线程

多线程和单线程的区别: 一个数据集进行排序,使用单线程还是多线程处理,他们的优劣

多线程编程的好处是什么? --充分利用并发

进程与线程的区别,进程切换需要切换哪些,线程共享进城什么?父进程的意义?子进程会得到父进程哪些?

进程(Process):进程是程序的一次执行。

线程(Thread),线程可以理解为进程中的执行的一段程序片段。在一个多任务环境中下面的概念可以帮助我们理解两者间的差别:

进程间是独立的,这表现在内存空间,上下文环境;线程运行在进程空间内。

一般来讲(不使用特殊技术)进程是无法突破进程边界存取其他进程内的存储空间;而线程由于处于进程空间内,所以同一进程所产生的线程共享同一内存空间。 同一进程中的两段代码不能够同时执行,除非引入线程。

线程是属于进程的,当进程退出时该进程所产生的线程都会被强制退出并清除。 线程占用的资源要少于进程所占用的资源。 进程和线程都可以有优先级 在线程系统中进程也是一个线程。可以将进程理解为一个程序的第一个线程。

进程通信方式

创建线程所消耗的资源:

还会涉及到CPU时间问题,创建过多的线程,会在线程切换的时候消耗CPU工作时间,当线程数达到一个极限值以后CPU就会什么都不用做了,只是在切换每一个线程,但是每个线程都没有实际的执行。 一般来说将线程数设置为CPU的2倍我认为是比较合理的,或者比CPU稍微多一点点。

线程所具有的资源:程序计数器、寄存器、栈。

这些线程具有自己的程序计数器、栈。但严格来说这些东西还在同一块内存区域上。所以不同线程之间是可以相互访问到的,虽然你不会这样做。

使用多线程的原因:

1.IO并发,可能是使用线程最多的地方

2.多核并发,(并行化)

3.易用性

线程的实现方式,有什么优缺点。

开启线程的方法、runnable和callable的区别

继承Thread类、实现Runnable接口、实现Callable接口,重写call()方法,在main函数中调用start()方法。

相同点:

  1. 两者都是接口;

  2. 两者都可用来编写多线程程序;

  3. 两者都需要调用Thread.start()启动线程;

不同点:

  1. 两者最大的不同点是:实现Callable接口的任务线程能返回执行结果;而实现Runnable接口的任务线程不能返回结果;

  2. Callable接口的call()方法允许抛出异常;而Runnable接口的run()方法的异常只能在内部消化,不能继续上抛;

注意点:

  • Callable接口支持返回执行结果,此时需要调用FutureTask.get()方法实现,此方法会阻塞主线程直到获取‘将来’结果;当不调用此方法时,主线程不会阻塞!

多线程在jvm中的具体调用情况 threadlocal

进程 / 线程

线程方法

wait()和sleep()的区别?java并发 wait 和sleep的区别

wait和sleep的区别

Wait(),sleep()区别?

ThreadLocal讲一下?

谈谈volatile关键字、讲一下volitale关键字,说一下为什么不保证原子性。 vector的底层原理、volatile的具体使用场景 、volatile的内部原理:JMM内存模型,冲刷线程中的缓存。

加锁方式

volatile,为什么单例模式二重校验锁下实例要声明为volatile

java中的锁机制 、 锁有哪些 他们的区别 哪个锁比较弱 lock的源码看过吗

Java中有哪些锁(我回答了synchronized,然后说了锁升级的过程,又说了ReentrantLock)

乐观锁和悲观锁,哪些锁是乐观锁,哪些是悲观锁(我说synchronized是悲观锁,乐观锁有哪些锁不了解)   

Java中包含的锁有哪些

  • 公平锁/非公平锁

  • 可重入锁

  • 独享锁/共享锁

  • 互斥锁/读写锁

  • 乐观锁/悲观锁

  • 分段锁

  • 偏向锁/轻量级锁/重量级锁

  • 自旋锁

乐观群与悲观锁的区别,使用场景,例子。

自旋锁这种设计有用吗?占用cpu,为什么呢?

问synchronized底层实现,偏向锁、自旋锁、轻量级锁、重量级锁,能否从重量级到轻量级,synchronized加在类和方法上的区别;为什么是可重入的?不可中断解释一下。synchronized,说一下它的锁的不同粒度

Synchronized用法,锁。

CAS底层通过什么实现 :发现AtomicBoolean的compareAndSet()调用的是unsafe里的compareAndSwapInt()方法,.unsafe是AtomicBoolean类中的静态成员变量。unsafe的compareAndSwapInt()方法是native方法。不同不同操作系统, 不同的处理器, 都要走不同的编指令cmpxchg()方法的实现.

synchronized,锁升级,讲一讲轻量锁与偏向锁,两个线程在轻量锁下有什么操作

synchronized和reentrantlock的区别,当都被interrupt时,有什么区别 、sychronized和lock、synchronized和reentrantLock的区别 --先说到了自旋锁,锁消除和锁粗化。最后扯到了Unsafe类就谈不下去了

在java中锁分为乐观锁和悲观锁、CAS原理?乐观锁和悲观锁?

synchronized就是一种悲观锁(独占锁),会导致其它所有需要锁的线程挂起,等待持有锁的线程释放锁。

而乐观锁采取了一种宽泛的态度,通过某种方式不加锁来处理资源,比如通过给记录加version来获取数据,性能较悲观锁有很大的提高

怎么加锁?synchronized 锁方法和锁代码块和显示锁ReentrantLock(提了超时获取锁)

synchronized在jvm的底层实现

AQS了解吗,有没有看过源码(没有,下一个);CAS的原理,CAS产生的问题,如何解决,CAS使用场景 、知道atomic类的原理吗? 聊一聊使用的场景。

CAS说一下,unsale类说一下,AQS说一下

JUC包看过吗 、juc看过哪些,说AQS的机制、公平锁和非公平锁的区别,源码级别

condition源码分析

volatile关键字有什么作用 、java锁,sync 和 lock、Volatile关键字

volatile保持内存可见性和防止指令重排序的原理,本质上是同一个问题,也都依靠内存屏障得到解决。

自旋锁和普通锁有什么区别:自旋锁写了个自旋锁伪代码,在死循环里不断试探锁位,占用处理机,发现锁被占用后不断读取,处于忙占用状态,不会挂起进入阻塞队列,如果是单核主机,没有其他核上面的线程给他释放锁,就死机了。

普通锁分互斥锁和条件变量,锁被占用时,立刻被挂起,task_struct内容修改,寄存器保护,保存打开的文件描述符,进程被换出内存,等待系统进程发现对应锁释放后再wake,换入内存。

jvm的锁优化有什么

那还有其他编译器的锁优化吗

Lock如何给线程分配锁的

同步 锁-锁什么了? 怎么进一步提高并发(通道)

synchronized关键字与Lock方法

线程池

BlockingQueue

各个队列使用场景、queue里面都有什么方法、各个方法仔细讲讲,都会出现什么情况,添加的方法有什么,都有什么不同出队列呢,

线程池介绍(fix,cache区别优缺点,主要参数)

有没有了解过线程池

线程池构造参数,为什么需要等待队列,等待队列无限大会出现什么情况(饥饿),什么时候可以不用等待队列,针对cpu密集型问题,可以采用什么类型得等待队列

线程池有几种类型,懵,没答上来,他想要的好像是ThreadFactory里面的提供的几个new方法,我说我的都是自己直接new线程池的。。

线程池的优点

多线程如何实现主存同步的

对线程池的了解、讲一下线程池的执行步骤,以及参数设置。线程池

提交一个任务到线程池,线程池怎么处理,你平时用现成的还是自定义重写线程池,newFixedThreadPool和newCacheThreadPool区别,饱和策略有哪些

线程池是怎么处理任务的(答了线程池的参数有核心线程池、最大线程池、任务队列等,然后扯了一下三者的合作机制)从executor到executorService,ThreadPoolExecutor,Executors,谈到了里面都有哪些方法?

ThreadPoolExecutor的具体工作流程

线程池的原理,作用。通常使用哪个类来实现?里面有哪些参数,都有什么作用。实现线程的方式,ThreadPoolExecutor的参数,任务队列是干嘛用的?

线程池的拒绝策略介绍下。

死锁

死锁,线程间有死锁吗 、死锁 、死锁

死锁、怎么预防 死锁产生条件:非抢占、互斥、占有并等待,循环等待、为什么会产生死锁、死锁发生的原因,我就只说了互相占有且等待,问还有吗?写一个死锁程序。

什么是死锁怎么避免 锁中有哪些可剥夺的方法

死锁,为什么会造成死锁,怎么解决死锁?锁成环,超时获取锁 、死锁的发生情况,死锁的条件,如何避免死锁

生产者消费者模式的理解和实现

synchronized锁对象和锁类的区别**(synchronized(A.class)和synchronized(object) 获取对象锁,获取类锁) 主要区别是同一个类的不同对象使用类锁会是同步的。

当数据正在更新,如何解决不同线程更新一个变量的问题。 ---使用synchoronized

主要问并发,锁,syncronized 与 lock 的区别,cas等

++i这个操作在多线程并发的情况下是否线程安全?答不安全。++i不是原子操作,分为两步完成了操作。

如果++i实现了原子操作,请问还存在线程安全问题吗?在面试官的引导下答出了多线程对变量的修改各个线程不可见。问怎么解决,使用volatile。

使用valtile怎么实现多线程对变量的修改相互可见?从主存本地栈的方向回答,线程取值会去主存中取而不是缓存。他说OK

如果实现++i的操作不使用锁进行同步实现线程安全,还有什么方法?说了AtomicInteger,说了volatile定义value值,使用Unsafe类中的方法操作内存中的数据

获取value在堆内存中的偏移量,再用CAS这个系统指令原语的CompareAndSwap方法进行对比更新i的值。

CAS的CompareAndSwap方法怎么实现对I值的更新?简单说了下,他又问,CAS在使用中会存在一定的问题,请问有哪些?我说了对旧的预期值A,可能出现

先修改为预期值B,后又修改为A,这样CAS算法在判断时,发现A没有变化,就不会进行交换与赋值,但实际上A的值经过了两次修改。对于这个问题使用版本号进

行解决。他说OK。

介绍下JAVA中乐观锁,悲观锁的区别。说了读锁写锁,SYNCHRONIZED,REENTRANTLOCK。以及使用的场景,说完了它问还有呢?我又稍微介绍了下共享锁,

说加了读锁可以再加共享锁,加了写锁就不能再加共享锁以及任何锁了。他说OK。我感觉这里说的没有达到他的要求。

不加锁会产生什么问题?读写顺序不一致,读到的不是想要的;

写了一半挂起,另一个线程写,然后挂起线程继续写,导致写错误(我也不知道对不对)

模拟游戏场景,在高并发情况下如何不用锁来保证安全性。可以利用单例线程池。

主要内容还是并发跟线程的知识,特别是锁机制和线程池,掌握的话机会大很多

还考察了多线程、线程安全的一些类的底层

事件驱动的异步编程存在的问题:

1.无法充分利用CPU的多核性(CPU的并行化机制)假如只有一个线程的话。所以

2.编程会很复杂

2.性能提升相对于单线程来说不会太多

 

线程带来的问题:

每个线程都要一些变量来说明他的状态,这些变量对于单个线程来说可以忽略,但是当这些线程数以百万计时,会对内存带来很大的影响。并且线程调度通常会有一个调度列表,要找到下一个执行的线程带来的代价是很大的。

这时可以使用事件驱动编程

一般来讲都会使用多线程和事件驱动结合起来做高性能的服务器。

多线程和多进程的区别:

一个进程就是一个单独运行的程序,只有一块内存空间,一大片可供进程使用的内存。在这块空间里可以有很多的进程

不同的进程之间不会有交集,但是在同一个进程里的线程可以共享这些空间。

当上下文切换时,是所有的线程都在切换吗?

我们使用的线程最终是由操作系统线程所提供的,当系统产生上下文切换的时候,操作系统是知道这一切的。

 

进程和线程的根本区别是程序计数器指针对应的虚地址空间,一组进程每个EIP指针有自己的虚地址空间,一组线程多个控制块对应同一个虚地址空间。在linux操作系统中控制块实现是task_struct,虚地址空间实现是mm_struct,Linux操作系统没有独立的线程数据结构,当一个线程分离出来,操作系统构造一个task_struct并使虚地址空间指针共享。性质上一个进程可以持有多个线程,一个线程可以创造线程,一个线程可以被取消,一个线程死亡导致整个进程死亡,一个进程死亡被其父节点回收,一个进程初始时可以视为单线程进程。进程被创建时操作系统复制整个进程的pcb,然后把进程控制块放入就绪队列的尾部,把进程符号插入进程树。进程只能由进程创建,操作系统启动时只有一个0号boot进程,1号进程是0号进程分裂出来的主进程,每个用户tty的父进程都是1号进程,当tty执行执行fork,tty分裂出一个进程作为子进程,当子进程被分离父进程由1号进程托管,他变成了守护进程(精灵进程daemon)

Linux进程和线程

计算机组成原理(冯诺依曼体系结构)

说一下Linux的多路复用方式有哪几种,netty采用的是哪一种(没答上来);多路io复用

进程通信有几种方式?

五大件 管道、共享内存、消息队列,信号量、FIFO文件访问,每个特性讲一下

select、poll、epoll

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内部定义的等待队列)。这也能节省不少的开销。

Linux调度方式有什么

linux内核的三种主要调度策略: 1,SCHED_OTHER 分时调度策略, 2,SCHED_FIFO实时调度策略,先到先服务 3,SCHED_RR实时调度策略,时间片轮转

实时进程将得到优先调用,实时进程根据实时优先级决定调度权值。分时进程则通过nice和counter值决定权值,nice越小,counter越大,被调度的概率越大,也就是曾经使用了cpu最少的进程将会得到优先调度。

SHCED_RR和SCHED_FIFO的不同: 当采用SHCED_RR策略的进程的时间片用完,系统将重新分配时间片,并置于就绪队列尾。放在队列尾保证了所有具有相同优先级的RR任务的调度公平。 SCHED_FIFO一旦占用cpu则一直运行。一直运行直到有更高优先级任务到达或自己放弃。 如果有相同优先级的实时进程(根据优先级计算的调度权值是一样的)已经准备好,FIFO时必须等待该进程主动放弃后才可以运行这个优先级相同的任务。而RR可以让每个任务都执行一段时间。

相同点: RR和FIFO都只用于实时任务。 创建时优先级大于0(1-99)。 按照可抢占优先级调度算法进行。 就绪态的实时任务立即抢占非实时任务。

所有任务都采用linux分时调度策略时: 1,创建任务指定采用分时调度策略,并指定优先级nice值(-20~19)。 2,将根据每个任务的nice值确定在cpu上的执行时间(counter)。 3,如果没有等待资源,则将该任务加入到就绪队列中。 4,调度程序遍历就绪队列中的任务,通过对每个任务动态优先级的计算权值(counter+20-nice)结果,选择计算结果最大的一个去运行,当这个时间片用完后(counter减至0)或者主动放弃cpu时,该任务将被放在就绪队列末尾(时间片用完)或等待队列(因等待资源而放弃cpu)中。 5,此时调度程序重复上面计算过程,转到第4步。 6,当调度程序发现所有就绪任务计算所得的权值都为不大于0时,重复第2步。

所有任务都采用FIFO时: 1,创建进程时指定采用FIFO,并设置实时优先级rt_priority(1-99)。 2,如果没有等待资源,则将该任务加入到就绪队列中。 3,调度程序遍历就绪队列,根据实时优先级计算调度权值(1000+rt_priority),选择权值最高的任务使用cpu,该FIFO任务将一直占有cpu直到有优先级更高的任务就绪(即使优先级相同也不行)或者主动放弃(等待资源)。 4,调度程序发现有优先级更高的任务到达(高优先级任务可能被中断或定时器任务唤醒,再或被当前运行的任务唤醒,等等),则调度程序立即在当前任务堆栈中保存当前cpu寄存器的所有数据,重新从高优先级任务的堆栈中加载寄存器数据到cpu,此时高优先级的任务开始运行。重复第3步。 5,如果当前任务因等待资源而主动放弃cpu使用权,则该任务将从就绪队列中删除,加入等待队列,此时重复第3步。

所有任务都采用RR调度策略时: 1,创建任务时指定调度参数为RR,并设置任务的实时优先级和nice值(nice值将会转换为该任务的时间片的长度)。 2,如果没有等待资源,则将该任务加入到就绪队列中。 3,调度程序遍历就绪队列,根据实时优先级计算调度权值(1000+rt_priority),选择权值最高的任务使用cpu。 4,如果就绪队列中的RR任务时间片为0,则会根据nice值设置该任务的时间片,同时将该任务放入就绪队列的末尾。重复步骤3。 5,当前任务由于等待资源而主动退出cpu,则其加入等待队列中。重复步骤3。

系统中既有分时调度,又有时间片轮转调度和先进先出调度: 1,RR调度和FIFO调度的进程属于实时进程,以分时调度的进程是非实时进程。 2,当实时进程准备就绪后,如果当前cpu正在运行非实时进程,则实时进程立即抢占非实时进程。 3,RR进程和FIFO进程都采用实时优先级做为调度的权值标准,RR是FIFO的一个延伸。FIFO时,如果两个进程的优先级一样,则这两个优先级一样的进程具体执行哪一个是由其在队列中的未知决定的,这样导致一些不公正性(优先级是一样的,为什么要让你一直运行?),如果将两个优先级一样的任务的调度策略都设为RR,则保证了这两个任务可以循环执行,保证了公平。

Ingo Molnar-实时补丁 为了能并入主流内核,Ingo Molnar的实时补丁也采用了非常灵活的策略,它支持四种抢占模式: 1.No Forced Preemption (Server),这种模式等同于没有使能抢占选项的标准内核,主要适用于科学计算等服务器环境。 2.Voluntary Kernel Preemption (Desktop),这种模式使能了自愿抢占,但仍然失效抢占内核选项,它通过增加抢占点缩减了抢占延迟,因此适用于一些需要较好的响应性的环境,如桌面环境,当然这种好的响应性是以牺牲一些吞吐率为代价的。 3.Preemptible Kernel (Low-Latency Desktop),这种模式既包含了自愿抢占,又使能了可抢占内核选项,因此有很好的响应延迟,实际上在一定程度上已经达到了软实时性。它主要适用于桌面和一些嵌入式系统,但是吞吐率比模式2更低。 4.Complete Preemption (Real-Time),这种模式使能了所有实时功能,因此完全能够满足软实时需求,它适用于延迟要求为100微秒或稍低的实时系统。 实现实时是以牺牲系统的吞吐率为代价的,因此实时性越好,系统吞吐率就越低。

命令:

linux的哪条指令可以查看cpu占用率

top -b -n 1 | grep Cpu

哪条指令可以查看进程状态

ps

 

操作系统段页式管理

####

并发编程,讲一下进程调度

答:cpu,中断,陷入,换页,tack_struct切换,PCB内容,内核态用户态切换bala

内存调度策略、操作系统:调度算法

我:FIFO、LLU、LRU

文件描述符讲一下:一个整数,inode的结构讲了一下,目录文件、无名文件讲了一下,文件描述符即是引用向inode的值

怎么实现两个进程同时访问文件描述符?进程通通信吗?可以共享内存mmap可以实现,讲了一下映射共享内存结构,另外还有shm,我不太熟,亲缘进程可以用管道,也可以socket 访问

现在要进程b和a访问同一个文件描述符,传什么参数?怎么传?

Linux了解吗?说下基本常用的命令?

(1) 你熟悉哪些linux命令

(2) 编辑一个文件怎么做

linux命令:递归创建目录

linux命令:查看端口信息

linux操作命令

线程里堆和栈是公有还是私有

进程和线程区别

linux 操作,find awk(都不会)

linux查看内存的命令

IO模型

linux底层实现的IO模型,epoll是什么 、io模型?(linux的IO模型记得是5种)linux五个io模型、I0多 路复用的三种实现方式?

Linux五种IO模型: 1.阻塞IO:当kernel没有数据可读时,io调用一直阻塞,直到kernel有数据时,将数据从kernel拷贝到用户空间,io调用才返回。

2.非阻塞IO:当kernel无数据可读时,io操作立即返回,当有数据可读时,将数据从kernel拷贝到用户空间才返回(拷贝过程仍然阻塞)。但需要用户进程轮询内核,直到读取到数据。

3.IO多路复用:监控多个文件描述符,将多个IO阻塞复用到一个select的阻塞上。

4.信号驱动IO:内核在描述符就绪时发送SIGIO信号,通过注册的信号处理程序读取数据。

5.异步IO:发出异步IO后,IO操作立即返回,当kernel有数据可读时,内核自动将数据拷贝到用户空间(不阻塞用户进程),拷贝完成后向用户进程发送信号。

缓存

计算机的一级缓存和二级缓存有什么用

CPU的二级缓存机制为什么要这样设计;

CPU的保护模式了解吗(不了解);

Linux的缓存有几级

 

计算机的结构:硬件和软件,里面的计算机结构

操作系统的死锁问题

操作系统缓存一致性怎么实现的?

操作系统多个操作的原子性如何保证?汇编Lock指令了解过吗(还有-个什么指令忘了)

缺页中断讲一下,讲进程挂起,保存状态,换出内存再唤醒、换入的上下文开销很高,如果进程很重要,或者进程挂起唤醒一次时间很长,比如每次把内存换完,就不值得挂起,不如空转处理机,使用自旋锁,避免上下文切换。

80486变长还是定长、80x86的数据是变长的还是定长的(懵);

 

 

 

我们在进行编程开发的时候,经常会涉及到同步,异步,阻塞,非阻塞,IO多路复用等概念,这几个概念有区别,但是有时候也容易混淆,如果不总结一下的话很容易受到困扰,下面就记录一下这几个概念的理解。

Unix网络编程中的五种IO模型

  • Blocking IO - 阻塞IO

  • NoneBlocking IO - 非阻塞IO

  • IO multiplexing - IO多路复用

  • signal driven IO - 信号驱动IO

  • asynchronous IO - 异步IO

由于signal driven IO在实际使用中并不常用,所以这里只讨论剩下的四种IO模型。

在讨论之前先说明一下IO发生时涉及到的对象和步骤,对于一个network IO,它会涉及到两个系统对象:

  • application 调用这个IO的进程

  • kernel 系统内核

那他们经历的两个交互过程是:

  • 阶段1 wait for data 等待数据准备

  • 阶段2 copy data from kernel to user 将数据从内核拷贝到用户进程中

之所以会有同步、异步、阻塞和非阻塞这几种说法就是根据程序在这两个阶段的处理方式不同而产生的。了解了这些背景之后,我们就分别针对四种IO模型进行讲解

Blocking IO - 阻塞IO

在linux中,默认情况下所有的socket都是blocking,一个典型的读操作流程大概如下图:

 

 

面试题常见考点

blocking I O.gif

 

当用户进程调用了recvfrom这个系统调用,kernel就开始了IO的第一个阶段:准备数据。对于network IO来说,很多时候数据在一开始还没有到达(比如,还没有收到一个完整的UDP包),这个时候kernel就要等待足够的数据到来。而在用户进程这边,整个进程会被阻塞。当kernel一直等到数据准备好了,它就会将数据从kernel中拷贝到用户内存,然后kernel返回结果,用户进程才解除block的状态,重新运行起来。

所以,blocking IO的特点就是在IO执行的两个阶段都被block了。

NoneBlockingIO - 非阻塞IO

linux下,可以通过设置socket使其变为non-blocking。当对一个non-blocking socket执行读操作时,流程是这个样子:

 

 

面试题常见考点

NonBlocking IO.gif

从图中可以看出,当用户进程发出recvfrom这个系统调用后,如果kernel中的数据还没有准备好,那么它并不会block用户进程,而是立刻返回一个结果(no datagram ready)。从用户进程角度讲 ,它发起一个操作后,并没有等待,而是马上就得到了一个结果。用户进程得知数据还没有准备好后,它可以每隔一段时间再次发送recvfrom操作。一旦kernel中的数据准备好了,并且又再次收到了用户进程的system call,那么它马上就将数据拷贝到了用户内存,然后返回。

所以,用户进程其实是需要不断的主动询问kernel数据好了没有。

IO multiplexing - IO多路复用

I/O多路复用(multiplexing)是网络编程中最常用的模型,像我们最常用的select、epoll都属于这种模型。以select为例:

 

 

面试题常见考点

multiplexing IO.gif

看起来它与blocking I/O很相似,两个阶段都阻塞。但它与blocking I/O的一个重要区别就是它可以等待多个数据报就绪(datagram ready),即可以处理多个连接。这里的select相当于一个“代理”,调用select以后进程会被select阻塞,这时候在内核空间内select会监听指定的多个datagram (如socket连接),如果其中任意一个数据就绪了就返回。此时程序再进行数据读取操作,将数据拷贝至当前进程内。由于select可以监听多个socket,我们可以用它来处理多个连接。

在select模型中每个socket一般都设置成non-blocking,虽然等待数据阶段仍然是阻塞状态,但是它是被select调用阻塞的,而不是直接被I/O阻塞的。select底层通过轮询机制来判断每个socket读写是否就绪。

当然select也有一些缺点,比如底层轮询机制会增加开销、支持的文件描述符数量过少等。为此,Linux引入了epoll作为select的改进版本。

asynchronous IO - 异步IO

异步I/O在网络编程中几乎用不到,在File I/O中可能会用到:

 

 

面试题常见考点

asynchronous IO.gif

这里面的读取操作的语义与上面的几种模型都不同。这里的读取操作(aio_read)会通知内核进行读取操作并将数据拷贝至进程中,完事后通知进程整个操作全部完成(绑定一个回调函数处理数据)。读取操作会立刻返回,程序可以进行其它的操作,所有的读取、拷贝工作都由内核去做,做完以后通知进程,进程调用绑定的回调函数来处理数据。

总结

我们来总结一下阻塞、非阻塞,同步和异步这两组概念。

先来说阻塞和非阻塞:

  • 阻塞调用会一直等待远程数据就绪再返回,即上面的阶段1会阻塞调用者,直到读取结束。

  • 而非阻塞无论在什么情况下都会立即返回,虽然非阻塞大部分时间不会被block,但是它仍要求进程不断地去主动询问kernel是否准备好数据,也需要进程主动地再次调用recvfrom来将数据拷贝到用户内存。

再说一说同步和异步:

  • 同步方法会一直阻塞进程,直到I/O操作结束,注意这里相当于上面的阶段1,阶段2都会阻塞调用者。其中 Blocking IO - 阻塞IO,Nonblocking IO - 非阻塞IO,IO multiplexing - IO多路复用,signal driven IO - 信号驱动IO 这四种IO都可以归类为同步IO。

  • 而异步方法不会阻塞调用者进程,即使是从内核空间的缓冲区将数据拷贝到进程中这一操作也不会阻塞进程,拷贝完毕后内核会通知进程数据拷贝结束。

下面的这张图很好地总结了之前讲的这五种I/O模型(来自Unix Network Programming)

 

 

面试题常见考点

io-modelposix-io-model-comparison.png

最后,在举个简单的例子帮助理解,比如我们怎样解决午饭问题:

A君喜欢下馆子吃饭,服务员点完餐后,A君一直坐在座位上等待厨师炒菜,什么事情也没有干,过了一会服务员端上饭菜后,A君就开吃了 -- 【阻塞I/O】

B君也喜欢下馆子,服务员点完餐后,B君看这个服务员姿色不错,便一直和服务员聊人生理想,并时不时的打听自己的饭做好了没有,过了一会饭也做好了,B君也撩到了美女服务员的微信号 -- 【非阻塞I/O 】顺便撩了个妹子☺

C君同样喜欢下馆子吃饭,但是C君不喜欢一个人下馆子吃,要呼朋唤友一起下馆子,但是这帮人到了饭店之后,每个人只点自己的,服务员一起给他们下单后,就交给后厨去做了,每做好一个人的,服务员就负责给他们端上来。做他们的服务员真滴好累???? -- 【IO多路复用】

D君比较宅,不喜欢下馆子,那怎么办呢?美团外卖啊(此处应有广告费:-D)手机下单后,自己啥也不用操心,只要等快递小哥上门就行了,这段时间可以撸好几把王者农药的了,嘿嘿 -- 【异步IO】

 

 

I/O多路复用(multiplexing)的本质是通过一种机制(系统内核缓冲I/O数据),让单个进程可以监视多个文件描述符,一旦某个描述符就绪(一般是读就绪或写就绪),能够通知程序进行相应的读写操作

select、poll 和 epoll 都是 Linux API 提供的 IO 复用方式。

相信大家都了解了Unix五种IO模型,不了解的可以 => 查看这里

[1] blocking IO - 阻塞IO [2] nonblocking IO - 非阻塞IO [3] IO multiplexing - IO多路复用 [4] signal driven IO - 信号驱动IO [5] asynchronous IO - 异步IO

其中前面4种IO都可以归类为synchronous IO - 同步IO,而select、poll、epoll本质上也都是同步I/O,因为他们都需要在读写事件就绪后自己负责进行读写,也就是说这个读写过程是阻塞的。

与多进程和多线程技术相比,I/O多路复用技术的最大优势是系统开销小,系统不必创建进程/线程,也不必维护这些进程/线程,从而大大减小了系统的开销。

在介绍select、poll、epoll之前,首先介绍一下Linux操作系统中基础的概念

  • 用户空间 / 内核空间 现在操作系统都是采用虚拟存储器,那么对32位操作系统而言,它的寻址空间(虚拟存储空间)为4G(2的32次方)。 操作系统的核心是内核,独立于普通的应用程序,可以访问受保护的内存空间,也有访问底层硬件设备的所有权限。为了保证用户进程不能直接操作内核(kernel),保证内核的安全,操作系统将虚拟空间划分为两部分,一部分为内核空间,一部分为用户空间。

  • 进程切换 为了控制进程的执行,内核必须有能力挂起正在CPU上运行的进程,并恢复以前挂起的某个进程的执行。这种行为被称为进程切换。因此可以说,任何进程都是在操作系统内核的支持下运行的,是与内核紧密相关的,并且进程切换是非常耗费资源的。

  • 进程阻塞 正在执行的进程,由于期待的某些事件未发生,如请求系统资源失败、等待某种操作的完成、新数据尚未到达或无新工作做等,则由系统自动执行阻塞原语(Block),使自己由运行状态变为阻塞状态。可见,进程的阻塞是进程自身的一种主动行为,也因此只有处于运行态的进程(获得了CPU资源),才可能将其转为阻塞状态。当进程进入阻塞状态,是不占用CPU资源的。

  • 文件描述符 文件描述符(File descriptor)是计算机科学中的一个术语,是一个用于表述指向文件的引用的抽象化概念。 文件描述符在形式上是一个非负整数。实际上,它是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表。当程序打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符。在程序设计中,一些涉及底层的程序编写往往会围绕着文件描述符展开。但是文件描述符这一概念往往只适用于UNIX、Linux这样的操作系统。

  • 缓存I/O 缓存I/O又称为标准I/O,大多数文件系统的默认I/O操作都是缓存I/O。在Linux的缓存I/O机制中,操作系统会将I/O的数据缓存在文件系统的页缓存中,即数据会先被拷贝到操作系统内核的缓冲区中,然后才会从操作系统内核的缓冲区拷贝到应用程序的地址空间。

Select

我们先分析一下select函数

int select(int maxfdp1,fd_set *readset,fd_set *writeset,fd_set *exceptset,const struct timeval *timeout);

【参数说明】 int maxfdp1 指定待测试的文件描述字个数,它的值是待测试的最大描述字加1。 fd_set *readset , fd_set *writeset , fd_set *exceptset fd_set可以理解为一个集合,这个集合中存放的是文件描述符(file descriptor),即文件句柄。中间的三个参数指定我们要让内核测试读、写和异常条件的文件描述符集合。如果对某一个的条件不感兴趣,就可以把它设为空指针。 const struct timeval *timeout timeout告知内核等待所指定文件描述符集合中的任何一个就绪可花多少时间。其timeval结构用于指定这段时间的秒数和微秒数。

【返回值】 int 若有就绪描述符返回其数目,若超时则为0,若出错则为-1

select运行机制

select()的机制中提供一种fd_set的数据结构,实际上是一个long类型的数组,每一个数组元素都能与一打开的文件句柄(不管是Socket句柄,还是其他文件或命名管道或设备句柄)建立联系,建立联系的工作由程序员完成,当调用select()时,由内核根据IO状态修改fd_set的内容,由此来通知执行了select()的进程哪一Socket或文件可读。

从流程上来看,使用select函数进行IO请求和同步阻塞模型没有太大的区别,甚至还多了添加监视socket,以及调用select函数的额外操作,效率更差。但是,使用select以后最大的优势是用户可以在一个线程内同时处理多个socket的IO请求。用户可以注册多个socket,然后不断地调用select读取被**的socket,即可达到在同一个线程内同时处理多个IO请求的目的。而在同步阻塞模型中,必须通过多线程的方式才能达到这个目的。

select机制的问题

  1. 每次调用select,都需要把fd_set集合从用户态拷贝到内核态,如果fd_set集合很大时,那这个开销也很大

  2. 同时每次调用select都需要在内核遍历传递进来的所有fd_set,如果fd_set集合很大时,那这个开销也很大

  3. 为了减少数据拷贝带来的性能损坏,内核对被监控的fd_set集合大小做了限制,并且这个是通过宏控制的,大小不可改变(限制为1024)

Poll

poll的机制与select类似,与select在本质上没有多大差别,管理多个描述符也是进行轮询,根据描述符的状态进行处理,但是poll没有最大文件描述符数量的限制。也就是说,poll只解决了上面的问题3,并没有解决问题1,2的性能开销问题。

下面是pll的函数原型:

 

int poll(struct pollfd *fds, nfds_t nfds, int timeout);
​
typedef struct pollfd {
        int fd;                         // 需要被检测或选择的文件描述符
        short events;                   // 对文件描述符fd上感兴趣的事件
        short revents;                  // 文件描述符fd上当前实际发生的事件
} pollfd_t;

poll改变了文件描述符集合的描述方式,使用了pollfd结构而不是select的fd_set结构,使得poll支持的文件描述符集合限制远大于select的1024

【参数说明】

struct pollfd *fds fds是一个struct pollfd类型的数组,用于存放需要检测其状态的socket描述符,并且调用poll函数之后fds数组不会被清空;一个pollfd结构体表示一个被监视的文件描述符,通过传递fds指示 poll() 监视多个文件描述符。其中,结构体的events域是监视该文件描述符的事件掩码,由用户来设置这个域,结构体的revents域是文件描述符的操作结果事件掩码,内核在调用返回时设置这个域

nfds_t nfds 记录数组fds中描述符的总数量

【返回值】 int 函数返回fds集合中就绪的读、写,或出错的描述符数量,返回0表示超时,返回-1表示出错;

Epoll

epoll在Linux2.6内核正式提出,是基于事件驱动的I/O方式,相对于select来说,epoll没有描述符个数限制,使用一个文件描述符管理多个描述符,将用户关心的文件描述符的事件存放到内核的一个事件表中,这样在用户空间和内核空间的copy只需一次。

Linux中提供的epoll相关函数如下:

 

int epoll_create(int size);
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);

1. epoll_create 函数创建一个epoll句柄,参数size表明内核要监听的描述符数量。调用成功时返回一个epoll句柄描述符,失败时返回-1。

2. epoll_ctl 函数注册要监听的事件类型。四个参数解释如下:

  • epfd 表示epoll句柄

  • op

    表示fd操作类型,有如下3种

    • EPOLL_CTL_ADD 注册新的fd到epfd中

    • EPOLL_CTL_MOD 修改已注册的fd的监听事件

    • EPOLL_CTL_DEL 从epfd中删除一个fd

  • fd 是要监听的描述符

  • event 表示要监听的事件

epoll_event 结构体定义如下:

 

struct epoll_event {
    __uint32_t events;  /* Epoll events */
    epoll_data_t data;  /* User data variable */
};
​
typedef union epoll_data {
    void *ptr;
    int fd;
    __uint32_t u32;
    __uint64_t u64;
} epoll_data_t;

3. epoll_wait 函数等待事件的就绪,成功时返回就绪的事件数目,调用失败时返回 -1,等待超时返回 0。

  • epfd 是epoll句柄

  • events 表示从内核得到的就绪事件集合

  • maxevents 告诉内核events的大小

  • timeout 表示等待的超时事件

epoll是Linux内核为处理大批量文件描述符而作了改进的poll,是Linux下多路复用IO接口select/poll的增强版本,它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率。原因就是获取事件的时候,它无须遍历整个被侦听的描述符集,只要遍历那些被内核IO事件异步唤醒而加入Ready队列的描述符集合就行了。

epoll除了提供select/poll那种IO事件的水平触发(Level Triggered)外,还提供了边缘触发(Edge Triggered),这就使得用户空间程序有可能缓存IO状态,减少epoll_wait/epoll_pwait的调用,提高应用程序效率。

  • 水平触发(LT):默认工作模式,即当epoll_wait检测到某描述符事件就绪并通知应用程序时,应用程序可以不立即处理该事件;下次调用epoll_wait时,会再次通知此事件

  • 边缘触发(ET): 当epoll_wait检测到某描述符事件就绪并通知应用程序时,应用程序必须立即处理该事件。如果不处理,下次调用epoll_wait时,不会再次通知此事件。(直到你做了某些操作导致该描述符变成未就绪状态了,也就是说边缘触发只在状态由未就绪变为就绪时只通知一次)。

LT和ET原本应该是用于脉冲信号的,可能用它来解释更加形象。Level和Edge指的就是触发点,Level为只要处于水平,那么就一直触发,而Edge则为上升沿和下降沿的时候触发。比如:0->1 就是Edge,1->1 就是Level。

ET模式很大程度上减少了epoll事件的触发次数,因此效率比LT模式下高。

总结

一张图总结一下select,poll,epoll的区别:

  select poll epoll
操作方式 遍历 遍历 回调
底层实现 数组 链表 哈希表
IO效率 每次调用都进行线性遍历,时间复杂度为O(n) 每次调用都进行线性遍历,时间复杂度为O(n) 事件通知方式,每当fd就绪,系统注册的回调函数就会被调用,将就绪fd放到readyList里面,时间复杂度O(1)
最大连接数 1024(x86)或2048(x64) 无上限 无上限
fd拷贝 每次调用select,都需要把fd集合从用户态拷贝到内核态 每次调用poll,都需要把fd集合从用户态拷贝到内核态 调用epoll_ctl时拷贝进内核并保存,之后每次epoll_wait不拷贝

epoll是Linux目前大规模网络并发程序开发的首选模型。在绝大多数情况下性能远超select和poll。目前流行的高性能web服务器Nginx正式依赖于epoll提供的高效网络套接字轮询服务。但是,在并发连接不高的情况下,多线程+阻塞I/O方式可能性能更好。


既然select,poll,epoll都是I/O多路复用的具体的实现,之所以现在同时存在,其实他们也是不同历史时期的产物

  • select出现是1984年在BSD里面实现的

  • 14年之后也就是1997年才实现了poll,其实拖那么久也不是效率问题, 而是那个时代的硬件实在太弱,一台服务器处理1千多个链接简直就是神一样的存在了,select很长段时间已经满足需求

  • 2002, 大神 Davide Libenzi 实现了epoll

 

 

 

select select能监控的描述符个数由内核中的FD_SETSIZE限制,仅为1024,这也是select最大的缺点,因为现在的服务器并发量远远不止1024。即使能重新编译内核改变FD_SETSIZE的值,但这并不能提高select的性能。 每次调用select都会线性扫描所有描述符的状态,在select结束后,用户也要线性扫描fd_set数组才知道哪些描述符准备就绪,等于说每次调用复杂度都是O(n)的,在并发量大的情况下,每次扫描都是相当耗时的,很有可能有未处理的连接等待超时。 每次调用select都要在用户空间和内核空间里进行内存复制fd描述符等信息。 poll poll使用pollfd结构来存储fd,突破了select中描述符数目的限制。 与select的后两点类似,poll仍然需要将pollfd数组拷贝到内核空间,之后依次扫描fd的状态,整体复杂度依然是O(n)的,在并发量大的情况下服务器性能会快速下降。 epoll epoll维护的描述符数目不受到限制,而且性能不会随着描述符数目的增加而下降。 服务器的特点是经常维护着大量连接,但其中某一时刻读写的操作符数量却不多。epoll先通过epoll_ctl注册一个描述符到内核中,并一直维护着而不像poll每次操作都将所有要监控的描述符传递给内核;在描述符读写就绪时,通过回掉函数将自己加入就绪队列中,之后epoll_wait返回该就绪队列。也就是说,epoll基本不做无用的操作,时间复杂度仅与活跃的客户端数有关,而不会随着描述符数目的增加而下降。 epoll在传递内核与用户空间的消息时使用了内存共享,而不是内存拷贝,这也使得epoll的效率比poll和select更高。

spring

spring 的核心思想是什么,依赖注入解决了什么问题,类 A 依赖 B,B 依赖 C,C 依赖 A 的时候怎么加载(这里我的描述大概不清晰,因为我不懂。。)

spring源码看过吗,如果给你时间,你觉得你能多久掌握(没看过,扯了一些别的);

看过Spring源码吗?说说Spring怎么让一个类在另外一个类之前加载

spring对象的依赖(具体问题记得不太清楚了,因为跟他说了框架只会搬砖)

ioc

spring ioc 源码、Spring的IOC能解释一下吗?底层代码怎么实现Ioc的、spring中的ioc介绍下。Spring IOC

aop

AOP

AOP的应用场景有哪些?

spring生明式事物

项目里Spring的事务是怎么管理的

Spring的事务是怎么实现的

Spring事务的注解实现、为什么这个注解可以实现事务、那为什么加注解可以实现,这个加载机制是怎么实现的,源码级别

五种管理方式:

数据库的四种+默认

那这个事务和数据库的事务有什么关联

AOP了解吗?简单地说了下两种不同的实现

spring aop、Spring AOP在项目中的具体应用

cglib底层实现

其他

spring循环依赖问题

Spring怎么解决循环依赖

spring源码看 过吗? spring怎么解决循环依赖问题?

spring优先加载子类是为啥

springMVC

springmvc运行流程

springBoot

SpringBoot特有的注解有哪些

springBoot auto注解

Springboot为啥可以配置这么少就能用 、Springboot自动配置原理

Spring和SpringBoot的区别?SpringBoot和Spring的区别有哪些

spring boot的了解 、SpringBoot如何加载,源码

SpringBoot自动配置原理?Springboot自动配置原理?如何实现一个starter?原理?springboot 自动化配置的实现

mybatis

MyBatis的优点

mybatis与hibemate的区别,hiberbate的优点,为什么用mybatis?

Hibernate功能强大,数据库无关性好,O/R映射能力强,如果你对Hibernate相当精通,而且对Hibernate进行了适当的封装,那么你的项目整个持久层代码会相当简单,需要写的代码很少,开发速度很快,非常爽。 ​ Hibernate的缺点就是学习门槛不低,要精通门槛更高,而且怎么设计O/R映射,在性能和对象模型之间如何权衡取得平衡,以及怎样用好Hibernate方面需要你的经验和能力都很强才行。 ​ iBATIS入门简单,即学即用,提供了数据库查询的自动对象绑定功能,而且延续了很好的SQL使用经验,对于没有那么高的对象模型要求的项目来说,相当完美。 ​ iBATIS的缺点就是框架还是比较简陋,功能尚有缺失,虽然简化了数据绑定代码,但是整个底层数据库查询实际还是要自己写的,工作量也比较大,而且不太容易适应快速数据库修改。

jdbc连接mysql的几个步骤、为什么要加载驱动呢,原理是什么、PreparedStatement和Statement区别、返回结果如何查询

Mybatis为什么实现接口就可以访问数据库

Mybatis的插件在Mybatis中是怎么运行的

是否使用过mybatis自定义函数?(无,我好菜)

JVM

java是自学的吗?除了ssm还了解哪些框架?

Java虚拟机运行时数据区域 、 JVM的存储区域、jvm内存区域划分?方法区的作用?(或者说方法区存储了哪些信息) 虚拟机栈的作用? 说一下JVM中方法区中存放的是什么;JVM内存管理机制、JVM模型说一下 程序计数器的作用 、JAVA虚拟机内存模型 :程序计数器,虚拟机栈、本地方法栈、Java堆(具体划分)、方法区

gc回收算法、JVM垃圾回收机制 、堆和栈的区别 、GC讲一讲、可达性分析中 gc root都包括哪些? 年轻代、老年代说一下,分别对应的GC算法 、垃圾回收器、垃圾回收的什么?gc, CMS有哪些步骤 、垃圾回收算法有哪些?如果判断哪个对象是垃圾对象?(引用计数法,可达性分析)哪些对象可以作为GC ROOT对象?垃圾回收、jvm新生代老年代、谈到了新生代的Eden和survivor区,为什么Eden区不用标记-清除算法: 因为新生代频繁创建对象 、标记清除算法,复制算法的原理 、垃圾回收机制的优劣 :不用手动管理垃圾回收,但是也造成了无法对垃圾进行管控。 垃圾回收算法中可达性分析算法原理,什么可以作为GC-roots的引用链 (虚拟机栈引用的对象,方法区类静态属性引用的对象,方法区常量引用的对象 )、GC?聊了根搜索进行可达性分析,标记,finalize(),(拯救),清理;介绍了GC算法(复制、标记整理、标记清除) 、为什么年轻代要用复制算法?复制算法的优缺点?聊了下无碎片空间,内存浪费,内存担保

要自己会分析哪些对象可以是GC ROOT对象,GC ROOT有一个特例:老年代的对象引用了新生代中的对象,那么这个对象也可以作为GC ROOT

CMS收集器说一下,stop-the-world的时候采用什么GC算法,要是采用标记整理算法需要停止程序吗?

jdk11中的ZGC垃圾收集器了解吗

类加载过程 、JVM的类加载流程,到解析到字节码 、实际运用中,ClassLoader都有了解什么 、如何获取当前的ClassLoader 、那可以保持建立多个ClassLoader吗? 为什么加载器加载出来的类不一样 ,类加载的机制,有哪些类加载器,分别负责加载哪些类。双亲委派的原理。如何打破双亲委派?类加载机制的双亲委派机制,类加载到什么地方、说一下JVM类加载的双亲委托机制为什么要这样设计(举了object的例子,还扯了Tomcat的类加载);双亲委派模式说一下 、双亲委派机制、好处,有没有自定义过类加载器、怎么打破双亲委派机制,像tomcat之类的应用、双亲委派机制?如何破坏?jvm双亲委派模型,和他的作用、了解双亲委派模型吗?tomcat类加载器 是怎样的?为什么tomcat类加载器要这么做?

对于一般的java类如下两种方法获得的ClassLoader通常都是同一个

  1. this.getClass.getClassLoader(); // 使用当前类的ClassLoader

  2. Thread.currentThread().getContextClassLoader(); // 使用当前线程的ClassLoader

  3. ClassLoader.getSystemClassLoader(); // 使用系统ClassLoader,即系统的入口点所使用的ClassLoader。

(注意,system ClassLoader与根ClassLoader并不一样。JVM下system ClassLoader通常为App ClassLoader)

jvm调优、jvm看过什么、jvm常用命令、jstat的参数,比如看一个线程的回收情况,怎么看、其他的命令呢

如何实现一个动态加载、实现哪些方法

jvm内存模型、那通过什么指令去实现其他工作内存无效的 、jvm内存模型,类的加载过程 、 Java内存模型?volatile作用

处理器指令重排、内存屏障,问处理器一般会怎么指令重排,是问重排序的三种:编译器优化的重排序、指令级并行的重排序和内存系统的重排序;

OOM出现的原因

如何确定内存泄露的位置 、内存泄漏如何解决 用jstat,jstack,jmap各种工具分析 (1.确定频繁full GC现象,找出进程唯一ID,用JPS 2.Jstat查看Full GC频次 3.jmap分析堆文件)

jvm内存中出现大图片,该如何处理,涉及到软引用

jstat和jmap具体用途

堆和栈区别

jvm调优

强引用,软引用,弱引用,虚引用

网络编程

网络编程知道吗

创建socket的过程 、从server端开始说吧,几个步骤 、accept操作之后,然后呢 、怎么解析这个信息呢,输出到什么流里呢

高性能RPC的理解 socket相关、互联网这块网络编程用的也挺多的,比如rpc框架什么的

Java里的IO这块你了解吗,区别 、BIO、NIO、AIO的对应类实现了解吗 、aio bio nio 、 IO流相关(简历里写了IO流,就不该写的我不会啊)

#

问了一下tcp挥手、TCP建立连接过程、为什么要有TIME_WAIT这个状态 、nagle算法介绍,nagle算法有什么问题(说了TCP粘包问题,面试官补充了一下时延问题) 、Tcp三次握手 、tcp三次握手,为什么三次 、三次握手第二个syn作用,捎带延时ack机制、网络三次握手、第二次确认啥用,没有造成啥后果?防过期请求SYN,服务器连接资源浪费耗尽、要是第二步也没了呢?服务器资源浪费耗尽,客户端也是、三次握手?去掉一次,优点、缺点?TCP三次握手过程 、三次握手、TCP三握手、TCP三次握手四次挥手 、四次挥手、TCP为什么是三次挥手不是两次?为什么是四次挥手,如果是三次挥手会怎样? (我这里答的是因为是全双工通信需要两边都断开连接,面试官说是本质就是为了确保发送了断开连接后保证另一方的数据要传输完成)

TCP/IP和UDP的区别?Tcp udp区别 、TCP和UPD的区别 、TCP和UDP区别、TCP面向连接,UDP尽力交付bala、tcp / udp

TCP/IP是如何保证可靠连接和可靠传输的?TCP怎么保证交付、滑动窗口,连续确认,画了个只有 1234 789的接收窗口,server的ack=5,client重新传56789···、 TCP怎么保证可靠传输(答了确认应答机制、拥塞控制、流量控制等)

TCP协议,拥塞控制/流量控制/滑动窗口的原理实现,TCP报文到ip层有什么变化、TCP拥塞控制、慢开始、拥塞避免 窗口、ssthresh、然后问我拥塞控制是怎么样的一个工作机制

TCP/IP位于那一层、Tcp/udp哪层,html哪层

HTTPS协议、http协议 、http报文内容有哪些、https的流程、https、 http和https协议、TCP,UDP,Http,Http请求头,Https。

输入:HTTPS://www.xx.com会发生什么?输入url发生的事情 、浏览器输入网址以后发生了哪些、客户端向服务端发送请求,到接受响应的一系列过程。浏览器输入url地址所用到的协议

Ip地址几位

404 500 304等代表啥 、常用的状态码

Request cookie session区别

OSI七层网络模型以及网络层有哪些协议

http get/post详解 restful架构

UDP怎么交付:画出UDP报文头,画出ip豹纹头,ip传到主机,再根据udp里的端口号传到对应端口

ip的包结构?抓过包吗?

Time_Wait在哪个阶段,它的作用

网页输入url过程是

Socket了解么

ping用到的协议

Get和Post区别

怎么设计http api

使用UDP如何实现可靠传输?(把TCP可靠传输那一套搬过来)

netty如何防止拆包粘包现象;

能不能自己实现一个RPC框架(说了gRPC和Thrift,中间居然忘了JSON串叫啥,有点懵);

netty属于CAP中的哪一部分;

TCP的快重传了解吗(不了解);

如何使用UDP实现可靠传输(问了为啥不直接用TCP,说是业务场景需要,没办法,瞎扯了一下);

说一下session与cookie的区别;

 

token和Session有什么区别,Session有什么不好的地方

Session存了很多用户数据,现在要对某个进程进行横向拓展,需要怎么做(这里的进程横向拓展当时我没听明白,回来想想会不会是指加服务器做集群的意思~)

计算机网络:304状态码,快重传

tcp怎么保证可靠传输(慢启动,拥塞避免,快重传,快恢复)

怎么解决脏包问题

应用层协议有哪些,讲一下?

计算机网络英雄联盟UDP TCP区别协议

UDP协议发生丢包如何处理,如何保证游戏不卡

tcp和udp有界*

计算机网络模型 OSI七层模型的产生

TCP和UDP的区别

  1. TCP(Transmission Control Protocol):传输控制协议

  2. UDP(User Datagram Protocol):用户数据报协议

 

主要从连接性(Connectivity)、可靠性(Reliability)、有序性(Ordering)、有界性(Boundary)、拥塞控制(Congestion or Flow control)、传输速度(Speed)、量级(Heavy/Light weight)、头部大小(Header size)等8个方面来讲:

 

\1. TCP是面向连接(Connection oriented)的协议,UDP是无连接(Connection less)协议;

TCP用三次握手建立连接:1) Client向server发送SYN;2) Server接收到SYN,回复Client一个SYN-ACK;3) Client接收到SYN_ACK,回复Server一个ACK。到此,连接建成。UDP发送数据前不需要建立连接。

 

\2. TCP可靠,UDP不可靠;

TCP丢包会自动重传,UDP不会。

 

\3. TCP有序,UDP无序;

消息在传输过程中可能会乱序,后发送的消息可能会先到达,TCP会对其进行重排序,UDP不会。

 

\4. TCP*,UDP有界;

TCP通过字节流传输,UDP中每一个包都是单独的。

 

\5. TCP有流量控制(拥塞控制),UDP没有;

主要靠三次握手实现。以及慢开始、拥塞避免、快重传、快恢复

 

\6. TCP传输慢,UDP传输快;

因为TCP需要建立连接、保证可靠性和有序性,所以比较耗时。这就是为什么视频流、广播电视、在线多媒体游戏等选择使用UDP。

 

\7. TCP是重量级的,UDP是轻量级的;

TCP要建立连接、保证可靠性和有序性,就会传输更多的信息,如TCP的包头比较大。

 

\8. TCP需要更多资源,UDP则要好上很多

 

\9. 应用场合不同:TCP一般应用在对可靠性要求比较高的场合,例如http,ftp等等。而UDP一般应用在对实时性要求较高场合,例如视频直播,大文件传输等等

 

小结:

TCP是面向连接的、可靠的、有序的、速度慢的协议;UDP是无连接的、不可靠的、无序的、速度快的协议。

TCP开销比UDP大,TCP头部需要20字节,UDP头部只要8个字节。

TCP*有拥塞控制,TCP有界无拥塞控制。

 

 

补充:

基于TCP的协议有:HTTP/HTTPS,Telnet,FTP,SMTP。

基于UDP的协议有:DHCP,DNS,SNMP,TFTP,BOOTP。

数据库

基础

数据库范式?

数据库设计注意事项

介绍下范式。第一范式和第二范式有什么区别?

acid、数据库事务和ACID 、 隔离性的理解

数据库的编码UTF-8和另外一个编码?(忘了是什么,没回答出来)

索引

Mysql数据库索引缺点

索引、唯一索引、Mysql的索引 、INNODB的索引,倒排索引、mysql索引

按数据结构分几种?

数据库索引的数据结构?

创建索引应该注意什么

为什么使用B+树做索引?Innodb的索引为什么用B+树,哈希索引和B+树索引作比较 、索引b+树、hash区别,为啥用的是b+树

实现了B+树,数据库懂吗,这是innoDB的后端实现,给我讲一下B树和B+树、

讲b+树先要讲b树,思想和二叉搜索树类似,二叉树二路搜索,i/o较高,b树又叫m路多路平衡搜索树···,是为了多级储存设计balabala,讲了一下搜索、插入删除,上下溢,节点既存key也寸value,调整消耗大,不适合顺序遍历。b+树解决顺序搜索问题,数据链式维护在硬盘,仅把key提出来做索引,类似B树,key定位到有指针指向物理位置,遍历即可。特点1.非叶节点仅存key,小,好维护,2.没个节点大小设置为扇区大小,查找下一节点顺序遍历,不用寻道了,快。

b加树叶子结点大小怎么控制、Mysql- 一个节点可以存放多少数据

那节点设置成多大好呢?

答:一般设置成扇区大小啊,扇区硬盘厂商设定的。

之前你说到块,块大小设置成多少呢?

答:一般都是4kB对齐,咦?为什么是4KB?哦我知道了,是最小换页单位,内存frame大小。

索引的种类?索引的位置、联合索引的使用

事物

MySQL并发导致的问题

数据库事物隔离

隔离级别、 隔离级别的理解、如何实现隔离性

MySQL的隔离级别,都解决了哪些问题?

mysql事务的实现(锁、mvcc )、数据库事务的理解

MVCC了解吗? 说说MVCC

数据库有哪些锁

数据库锁

优化

mysql优化知道哪些(答了sql语句优化、索引优化、表结构优化、服务器性能优化)

mysql如何进行查询优化(主要讲了索引)

SQL如何优化?

SQL优化

问数据库千万数据的表如何优化

顺序是: 第一优化你的sql和索引;

第二加缓存,memcached,redis;

第三:做主从复制或主主复制,读写分离,可以在应用层做,效率高,也可以用三方工具,第三方工具推荐360的atlas,其它的要么效率不高,要么没人维护;

第四:mysql自带分区表,先试试这个,对你的应用是透明的,无需更改代码,但是sql语句是需要针对分区表做优化的,sql条件中要带上分区条件的列,从而使查询定位到少量的分区上,否则就会扫描全部分区,另外分区表还有一些坑,在这里就不多说了;

第五:先做垂直拆分,其实就是根据你模块的耦合度,将一个大的系统分为多个小的系统,也就是分布式系统;

第六:水平切分,针对数据量大的表,这一步最麻烦,最能考验技术水平,要选择一个合理的sharding key,为了有好的查询效率,表结构也要改动,做一定的冗余,应用也要改,sql中尽量带sharding key,将数据定位到限定的表上去查,而不是扫描全部的表;

mysql数据库一般都是按照这个步骤去演化的,成本也是由低到高;

有人也许要说第一步优化sql和索引这还用说吗?的确,大家都知道,但是很多情况下,这一步做的并不到位,甚至有的只做了根据sql去建索引,根本没对sql优化(中枪了没?),除了最简单的增删改查外,想实现一个查询,可以写出很多种查询语句,不同的语句,根据你选择的引擎、表中数据的分布情况、索引情况、数据库优化策略、查询中的锁策略等因素,最终查询的效率相差很大;优化要从整体去考虑,有时你优化一条语句后,其它查询反而效率被降低了,所以要取一个平衡点;即使精通mysql的话,除了纯技术面优化,还要根据业务面去优化sql语句,这样才能达到最优效果;你敢说你的sql和索引已经是最优了吗?

再说一下不同引擎的优化,myisam读的效果好,写的效率差,这和它数据存储格式,索引的指针和锁的策略有关的,它的数据是顺序存储的(innodb数据存储方式是聚簇索引),他的索引btree上的节点是一个指向数据物理位置的指针,所以查找起来很快,(innodb索引节点存的则是数据的主键,所以需要根据主键二次查找);myisam锁是表锁,只有读读之间是并发的,写写之间和读写之间(读和插入之间是可以并发的,去设置concurrent_insert参数,定期执行表优化操作,更新操作就没有办法了)是串行的,所以写起来慢,并且默认的写优先级比读优先级高,高到写操作来了后,可以马上插入到读操作前面去,如果批量写,会导致读请求饿死,所以要设置读写优先级或设置多少写操作后执行读操作的策略;myisam不要使用查询时间太长的sql,如果策略使用不当,也会导致写饿死,所以尽量去拆分查询效率低的sql,

innodb一般都是行锁,这个一般指的是sql用到索引的时候,行锁是加在索引上的,不是加在数据记录上的,如果sql没有用到索引,仍然会锁定表,mysql的读写之间是可以并发的,普通的select是不需要锁的,当查询的记录遇到锁时,用的是一致性的非锁定快照读,也就是根据数据库隔离级别策略,会去读被锁定行的快照,其它更新或加锁读语句用的是当前读,读取原始行;因为普通读与写不冲突,所以innodb不会出现读写饿死的情况,又因为在使用索引的时候用的是行锁,锁的粒度小,竞争相同锁的情况就少,就增加了并发处理,所以并发读写的效率还是很优秀的,问题在于索引查询后的根据主键的二次查找导致效率低;

ps:很奇怪,为什innodb的索引叶子节点存的是主键而不是像mysism一样存数据的物理地址指针吗?如果存的是物理地址指针不就不需要二次查找了吗,这也是我开始的疑惑,根据mysism和innodb数据存储方式的差异去想,你就会明白了,我就不费口舌了!

所以innodb为了避免二次查找可以使用索引覆盖技术,无法使用索引覆盖的,再延伸一下就是基于索引覆盖实现延迟关联;不知道什么是索引覆盖的,建议你无论如何都要弄清楚它是怎么回事!

尽你所能去优化你的sql吧!说它成本低,却又是一项费时费力的活,需要在技术与业务都熟悉的情况下,用心去优化才能做到最优,优化后的效果也是立竿见影的!

写查询的sql语句,如何优化笛卡儿积

MySQL数据库常用性能调优技巧

1,设计方面,考虑最优字段,尽量设置非空数据,使用数值型数据,

3,使用事务或锁定表,来保证数据库数据完整性 4,使用索引,索引能够更有效率的查询数据 5,查询时最好不要使用 * 号进行查询概括,在有索引的字段尽量不要使用函数操作,尽量不要使用like进行模糊查询,因为影响系统性能

1、选取最适用的字段属性 //代替 *

2、使用连接(JOIN)来代替子查询(Sub-Queries)

3、使用联合(UNION)来代替手动创建的临时表

4、事务 //对于某些绑定不可分割的操作,要使用事务,以免造成数据冗乱而破坏了数据。

5、锁定表 //例如mysql的主从复制,读写分离,等等。这里做详细介绍。

6、使用外键 //锁定表的方法可以维护数据的完整性,但是它却不能保证数据的关联性。这个时候我们就可以使用外键。

7、使用索引 //索引是提高数据库性能的常用方法,其采用B+树的结构进行存储,极大的提高了检索速度。

8、优化的查询语句 //使用索引进行查询,如果写的条件不恰当,就不能发挥出索引的作用了,而且索引是占物理内存的,反而适得其反了。

分页

Mysql怎么分页

数据量大的时候数据库分页操作有什么问题,怎么优化

分库分表

Mysql数据量很大并且已使用索引查询还很慢如何解决?分库分表。如何实现,该注意什么?

一个结果表有classid、subjectId、studentId、score字段,查出每门课程的前三名的学生和班级

varchar(50)表示什么意思,存的字节还是字符,现在你用的mysql版本存的字节还是字符

自增主键,如果有10条数据,如果将id=10的数据删除,那再插入一条数据id从几开始?如果重启了呢?用两个存储引擎的底层想一想。

group by和order by的使用顺序,如果还有判断条件,应该怎么做?

金额字段一般用什么类型存储

where和having区别

 

delete from id <= 1000 和 select 出所有要删除的 id 后传给 delete 删除哪个更快,id是主键

 

数据库事务的隔离级别

可重复读是指什么 可重复读的实现

数据库有哪些引擎,InnoDB 和 MyISAM 的区别,聚簇索引和非聚簇索引的区别

多个Java程序并发访问数据库,怎么实现数据库的线程事务安全 :对行加锁

Innodb和MyIsam区别

 

 

 

数据库隔离级别

一条sql比较慢,有哪些方面的原因?给个答案链接

https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485185&idx=1&sn=66ef08b4ab6af5757792223a83fc0d45&chksm=cea248caf9d5c1dc72ec8a281ec16aa3ec3e8066dbb252e27362438a26c33fbe842b0e0adf47&token=79317275&lang=zh_CN#rd

Mysql为何不使用hash而使用B+ Tree,说出hash的缺点(答的不好);

 

 

 

数据库什么情况下分表

数据库索引的使用有啥要注意的地方

数据库索引innodb和myisam区别 数据库的存储 数据库怎么优化 索引越多越好吗(不是)为什么

事务隔离级别?并发问题?分别如何解决?

Mysql优化方式有哪些?如何查看效率?

Mysql索引如何设计,设计原则?

MySQL你了解些什么?索引(聚簇、非聚簇、最左匹配),范式,explain,processlist指令,慢查询日志等

MySQL索引,为什么要建索引?怎么建索引?加快查询速度,where条件查询后面常用到的列建立索引

还有一些在B树B+树和红黑树的衍生问题(太难了)

 

扩展问题

redis调优,redis集群、 redis 跳表、Redis除了缓存之外,还可以做什么?redis理解、redis结构底层实现、 redis单线程 多路io复用 、Redis的基本使用 、redis中的LRU算法?怎么实现的?

你说你用到了Redis,比如有两个事务A和B去操作数据,会出现什么问题(我说会出现丢失修改,面试官说不对,面试官说了一堆,我也没听明白,就是说什么还是原来老数据,什么不是新数据)

Redis是用来干吗的,我说存热点数据?然后问,哪些是热点数据?(我说频繁访问访问的是热数据,面试官好像说是更新频繁吗)

MySQL和redis的双写一致性问题(是先删除数据,在更新数据库吗)

如何同时使用同一个包的不同版本

作为一个启动应用程序的容器,需要管理内部加载的所有jar,对应用程序的可见性范围,否则会造成类加载混乱,造成应用无法正常使用。比如常见的Tomcat、SOFAArk等类隔离机制。

源码分析、学习源码如何深入学习的 、如果去了解spring的启动过程,你怎么去了解

首先当然是跟着编码。看调用过程,调了哪些方法,这些方法内部是怎么实现的,以及结合源码中的注释一起来看,遇到看不懂的地方先暂且放一放,等整个流程都看完了仍然没有答案的时候在网上找解释,然后看别人的博客,是否与自己的理解一样,也算是再复习一遍。

tomcat启动的流程,要加载什么资源

那你知道有其他的连接池,各自有什么区别

那你感觉连接池的功能都有什么

连接池的作用就是为了提高性能。

连接池的作用:连接池是将已经创建好的连接保存在池中,当有请求来时,直接使用已经创建好的连接对数据库进行访问。这样省略了创建连接和销毁连接的过程。这样性能上得到了提高。

基本原理是这样的:

(1)建立数据库连接池对象(服务器启动)。 (2)按照事先指定的参数创建初始数量的数据库连接(即:空闲连接数)。 (3)对于一个数据库访问请求,直接从连接池中得到一个连接。如果数据库连接池对象中没有空闲的连接,且连接数没有达到最大(即:最大活跃连接数),创建一个新的数据库连接。 (4)存取数据库。 (5)关闭数据库,释放所有数据库连接(此时的关闭数据库连接,并非真正关闭,而是将其放入空闲队列中。如实际空闲连接数大于初始空闲连接数则释放连接)。 (6)释放数据库连接池对象(服务器停止、维护期间,释放数据库连接池对象,并释放所有连接)。

2.如果不使用连接池会出现的情况:

a.占用服务器的内存资源 b.导致服务器的速度非常慢

3 .应用连接池的三种方式:

a.自定义连接池 b.使用第三方连接池 c.使用服务器自带的连接池

基于Java的开源数据库连接池主要有:C3P0ProxoolDBCPBoneCPDruid等。

动手去编译过JDK源码吗

如何去验证版本的冲突的,比如jdk1.6到jdk1.7

Java里怎么实现缓存一致性的

通过在总线加LOCK#锁的方式(硬件层面)

缓存一致性协议(硬件层面)

cpu100如何定位

步骤一、找到最耗CPU的进程:执行top -c ,显示进程运行信息列表,键入P (大写p),进程按照CPU使用率排序

步骤二:找到最耗CPU的线程:top -Hp 10765(最消耗cpu的进程pid) ,显示一个进程的线程运行信息列表,键入P (大写p),线程按照CPU使用率排序

步骤三:将线程PID转化为16进制:printf,方法:printf “%x\n” 10804。之所以要转化为16进制,是因为堆栈里,线程id是用16进制表示的。

步骤四:查看堆栈,找到线程在干嘛。工具:pstack/jstack/grep,方法:jstack 10765 | grep ‘0x2a34’ -C5 --color

  • 打印进程堆栈

  • 通过线程id,过滤得到线程堆栈

找到了耗CPU高的线程对应的线程名称“AsyncLogger-1”,以及看到了该线程正在执行代码的堆栈。

看什么书,上什么网站 遇到bug咋处理(直接说了Stack Overflow)

Linux性能调优,如何发现及诊断问题

CAP理论

ZK和Eureka保证了哪几项?

什么是分布式锁?

分布式Session存在什么限制?

 

MD5,问我了解MD5吗,MD5能加密吗,可以由MD5得到原来的数据吗?我说了一些,后来深问我就直接说我不是很了解了。

使用Nginx做什么?

负载均衡算法有哪些?

Redis雪崩,缓存失效,缓存不一样(这里全部都是发散性的题目)

开放试题,怎么估算城市一天的车流量 。一个城市对应多个ip,一共三个城市,请问给出一个ip怎么快速定位是哪个城市的(想了好久没有思路,最后面试官提示用数据结构来解决,回答了前缀树)

设计中间件 消息队列 状态

给你1个g的数据,里面存了电话号码,给定一个电话号码,确认这个电话号码在不在里面

一道场景题,50G的key找出出现频率前100key

字符串有20G内存存不下,怎么办

字符串有1PB,硬盘都装不下,怎么办

(面试官是跟着我的思路走的,其中聊到了动态扩容,生产者消费者等很多问题。)

1000万个用户,10秒发送一次心跳,下线的就不发了,所以系统10秒后才能知道他下线了,怎么能快速的查找到已经下线的用户?

1000万个电话号码,牺牲空间来达到时间效率,如何查重并排序

一个文件中大量的数,如何给他去重,还是大量,内存放不下

一栋楼10层,每层有钻石,你坐电梯,只能上,只能拿一次,你用什么策略?

爬虫,爬取大量url,如何识别一个url有没有被爬过,注意大量,内存放不下

讲一下秒杀系统的整个架构

 

然后问实习相关的内容,问遇到过什么问题,我说了一个Guava缓存、Redis和数据库结合使用的三级缓存,发生缓存雪崩,怎么解决的?

kafka,如果消费者端消费了一小段任务,突然挂掉了,然后服务端重新发消息让其他消费者执行,挂掉的消费者本来已经执行了一点任务,但是offset并不是在挂掉时候的那里, 然后让其他消费者执行,会重复执行,该怎么办?还有一些问题我忘了。

zookeeper的原理,作用。主要用推模式还是拉模式。

Zookeeper的结点类型?

PERSISTENT 持久化节点

PERSISTENT_SEQUENTIAL 顺序自动编号持久化节点,这种节点会根据当前已存在的节点数自动加 1

EPHEMERAL 临时节点, 客户端session超时这类节点就会被自动删除

EPHEMERAL_SEQUENTIAL 临时自动编号节点

zookeeper的监听机制了解吗?是怎么实现的?,结点它是自动删除的吗?

ZooKeeper允许用户在指定节点上注册一些 Watcher, 并且在一些特定事件触发的时候,ZooKeeper 服务端会将事件通知到感兴趣的客户端上去。该 机制是 ZooKeeper 实现分布式协调服务的重要特性。

选举机制

针对 Master 选举的需求,通常情况下,我们可以选择常见的关系型数据库中的主键特性来 实现:希望成为 Master 的机器都向数据库中插入一条相同主键ID的记录,数据库会帮我们进行 主键冲突检查,也就是说,只有一台机器能插入成功——那么,我们就认为向数据库中成功插入数据 的客户端机器成为Master。

依靠关系型数据库的主键特性确实能够很好地保证在集群中选举出唯一的一个Master。
​
但是,如果当前选举出的 Master 挂了,那么该如何处理?谁来告诉我 Master 挂了呢?

显然,关系型数据库无法通知我们这个事件。但是,ZooKeeper 可以做到!

利用 ZooKeepr 的强一致性,能够很好地保证在分布式高并发情况下节点的创建一定能够

保证全局唯一性,即 ZooKeeper 将会保证客户端无法创建一个已经存在的 数据单元节点。 也就是说,如果同时有多个客户端请求创建同一个临时节点,那么最终一定只有一个客户端 请求能够创建成功。利用这个特性,就能很容易地在分布式环境中进行 Master 选举了。

成功创建该节点的客户端所在的机器就成为了 Master。同时,其他没有成功创建该节点的

客户端,都会在该节点上注册一个子节点变更的 Watcher,用于监控当前 Master 机器是否存 活,一旦发现当前的Master挂了,那么其他客户端将会重新进行 Master 选举。

这样就实现了 Master 的动态选举。

项目是自己做的还是跟别人一起合作的

如果你和同事对开发意见不一,你会怎么处理

有同事想要把代码写的很完善,你想把代码写的简单,如何处理

一个服务启动过慢,假设加载了大量的类,你该怎么做?

如果考虑是GC问题,用什么命令?

你说用到rabbitMQ,那么rabbitmq如何保证不被重复消费?

dubbo的服务暴露过程

你说用到dubbo了,那么其他模块是怎么通过dubbo调用的。答了dubbo的工作流程,就是那几个结点的调用关系,

你都熟悉哪些框架?Netty用过吗?

分布式锁 锁过期 锁误删 锁超时之类的

你的项目是怎么打包、部署的?

vim怎么整行删除 :dd:删除游标所在的一整行(常用)

说一说cap理论?eureka是cp还是ap?你知道哪个框架是ap的吗?zookeeper。 zookeeper如何进行选举?

CAP了不了解(不了解);

CAP理论

一致性(Consistency) : 客户端知道一系列的操作都会同时发生(生效) 可用性(Availability) : 每个操作都必须以可预期的响应结束 分区容错性(Partition tolerance) : 即使出现单个组件无法可用,操作依然可以完成

服务器如何处理多个session(分布式session,没答上来);

分布式怎么存储Session

粘性session:将用户锁定到某一个服务器上

服务器session复制:任何一个服务器上的session发生改变(增删改),该节点会把这个 session的所有内容序列化,然后广播给所有其它节点,不管其他服务器需不需要session,以此来保证Session同步。

session共享机制:使用分布式缓存方案比如memcached、Redis,但是要求Memcached或Redis必须是集群。根据cookie中存储的SessionId找session,找不到时,再去相应的memcached上去session,找到之后将其复制到备tomcat上。

session持久化到数据库:

为啥用git不用其他的

CPU为啥有多级缓存

一级缓存和二级缓存,少数高端处理器还集成了三级缓存。

一级缓存可分为一级指令缓存和一级数据缓存。一级指令缓存用于暂时存储并向CPU递送各类运算指令;一级数据缓存用于暂时存储并向CPU递送运算所需数据,这就是一级缓存的作用。

二级缓存就是一级缓存的缓冲器:一级缓存制造成本很高因此它的容量有限,二级缓存的作用就是存储那些CPU处理时需要用到、一级缓存又无法存储的数据。

三级缓存和内存可以看作是二级缓存的缓冲器,它们的容量递增,但单位制造成本却递减。需要注意的是,无论是二级缓存、三级缓存还是内存都不能存储处理器操作的原始指令,这些指令只能存储在CPU的一级指令缓存中,而余下的二级缓存、三级缓存和内存仅用于存储CPU所需数据。

Redis基本数据类型,主从同步

Zookeeper 节点,watch

分布式锁怎么写的 、分布式锁怎么写的

实习负责什么

怎么与前端交互的

说说实习期间一个具体接口的实现 (全过程)

Java8使用过什么新特性,用在哪里,意义

topK问题?(分两种情况,一种可以放进内存中处理,一种不能放进内存中处理)

有一个3.7亿的数据中如何判断某一个数据是否存在?bitset

dubbo和spring cloud的区别?

zuul网关优化?(没答上?)(学长告诉我zuul的IO模型是阻塞的,换成gateway)

讲讲JWT token?

消息队列如何保证幂等性?如何保证消息不丢失?

讲一讲倒排索引的底层原理?为什么比mysql索引快?

ActiveMQ如何保证消息不丢失(懵了,扯了一下ack);

说一下Tomcat的消息处理过程(reactor模式,容器,模板方法模式);

让你实现一个LRU算法,你该如何实现;

说说项目中的Redis分布式锁是怎么实现的,MQ怎么保证消息的可靠性传递

用Java的API来实现一个定时器要怎么做(项目中有写用到Quartz定时器)

面试官边看简历边聊简历项目中的一些点(会根据你简历项目来问,所以还是对自己简历上的项目有可能被问到的问题多加准备)

用Java的API来实现一个定时器要怎么做(这个问题和一面一样~)

spring cloud有哪些组件,注册中心,熔断原理

redis项目中

ES倒排索引

mq

秒杀设计

对高并发、分布式有没有了解

平时用过什么数据结构或者集合的类 哪些类用到了链表 hashmap用了哪些数据结构 1.8里什么时候链表转成红黑树 为什么长度>8(为什么是8) arraylist和linkedlist区别 栈和队列的区别 查找时间复杂度分别是 栈的应用 hashmap的hash过程 为什么右移16位

如果我在txt文件里存储一个字典 怎么去查找 怎么优化查询速度 (这里我真的没get到想让我答什么 好像一直没答到点子上) 和我讲了一下hibernate怎么优化查询速度的 感觉自己答的很差估计是凉了

加密算法?

redis单线程为啥快

消息队列,底层实现

如果有一亿条记录如何优化?

ES检索为什么比MySQL快?

什么是倒排索引

倒排索引的三部分?分词属于哪部分?

倒排索引为什么不使用B树或B+树?使用B树或B+数有什么缺点?5. B树和B+树的区别?MySQL为什么不使用红黑树

redis的数据结构有哪些? zset底层怎么实现的?

zset的跳跃表可以用红黑树吗?跳跃表怎么实现自平衡?

rocketmq 的架构

brocker 是集群的吗 slave 挂掉怎么办 consumer 从哪里得到消息

下游 消费了 consumer 后挂掉怎么办,执行了操作但是没有返回通知

下游 A B C 中其中一个挂掉了,其他的消费成功了怎么办