剑三神龙现世重置版重置版分配者分配模式怎么插装备给roll点最高的玩家?

意大利留学生Java后台开发面经_讨论区_牛客网
拼多多面试:
1,·&&CHROME给每个tab开了进程,为什么? 其实就是问线程与进程区别 :
·&·&&进程是具有一定独立功能的程序、它是系统进行资源分配和调度的一个独立单位,重点在系统调度和单独的单位,也就是说进程是可以独立运行的一段程序。
·&线程是进程的一个实体,是CPU调度和分派的基本单位,他是比进程更小的能独立运行的基本单位,线程自己基本上不拥有系统资源。在运行时,只是暂用一些计数器、寄存器和栈 。
·&调度:线程作为调度和分配的基本单位,进程作为拥有资源的基本单位。
·&并发性:不仅进程之间可以并发执行,同一个进程的多个线程之间也可以并发执行。
·&拥有资源:进程是拥有资源的一个独立单位,线程不拥有系统资源,但可以访问隶属于进程的资源。
1 线程与线程间通信
1.1 基本概念以及线程与进程之间的区别联系
·&关于进程和线程,首先从定义上理解就有所不同:
1.&进程是具有一定独立功能的程序、它是系统进行资源分配和调度的一个独立单位,重点在系统调度和单独的单位,也就是说进程是可以独立运行的一段程序。
2.&线程是进程的一个实体,是CPU调度和分派的基本单位,他是比进程更小的能独立运行的基本单位,线程自己基本上不拥有系统资源。在运行时,只是暂用一些计数器、寄存器和栈 。
他们之间的关系
1.&一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程(通常说的主线程)。
2.&资源分配给进程,同一进程的所有线程共享该进程的所有资源。
3.&线程在执行过程中,需要协作同步。不同进程的线程间要利用消息通信的办法实现同步。
4.&处理机分给线程,即真正在处理机上运行的是线程。
5.&线程是指进程内的一个执行单元,也是进程内的可调度实体。
从三个角度来剖析二者之间的区别
1.&调度:线程作为调度和分配的基本单位,进程作为拥有资源的基本单位。
2.&并发性:不仅进程之间可以并发执行,同一个进程的多个线程之间也可以并发执行。
3.&拥有资源:进程是拥有资源的一个独立单位,线程不拥有系统资源,但可以访问隶属于进程的资源。
1.2 多线程间通信方式
·&共享变量
·&wait/notify机制
·&Lock/Condition机制
1.2.1 共享变量
·&线程间发送信号的一个简单方式是在共享对象的变量里设置信号值。线程A在一个同步块里设置boolean型成员变量hasDataToProcess为true,线程B也在同步块里读取hasDataToProcess这个成员变量。这个简单的例子使用了一个持有信号的对象,并提供了set和check方法:
public class MySignal{
protected boolean hasDataToProcess =
public synchronized boolean hasDataToProcess(){
return this.hasDataToP
public synchronized void setHasDataToProcess(boolean hasData){
this.hasDataToProcess = hasD
·&线程A和B必须获得指向一个MySignal共享实例的引用,以便进行通信。如果它们持有的引用指向不同的MySingal实例,那么彼此将不能检测到对方的信号。需要处理的数据可以存放在一个共享缓存区里,它和MySignal实例是分开存放的。
1.2.2 wait()/notify机制
·&为了实现线程通信,我们可以使用Object类提供的wait()、notify()、notifyAll()三个方法。调用wait()方法会释放对该同步监视器的锁定。这三个方法必须由同步监视器对象来调用,这可分成两种情况:
o&对于使用synchronized修饰的同步方法,因为该类的默认实例是(this)就是同步监视器,所以可以直接调用这三使用个方法。
o&对于synchronized修饰的同步代码块,同步监视器是synchronized括号里的对象,所以必须使用该对象调用这三个方法。
假设系统中有两条线程,这两条线程分别代表取钱者和存钱者。现在系统有一种特殊的要求,系统要求存款者和取钱者不断的实现存款和取钱动作,而且要求每当存款者将钱存入指定账户后,取钱者立即将钱取走.不允许存款者两次存钱,也不允许取钱者两次取钱。
我们通过设置一个旗标来标识账户中是否已有存款,有就为true,没有就标为false。具体代码如下:
首先我们定义一个Account类,这个类中有取钱和存钱的两个方法,由于这两个方法可能需要并发的执行取钱、存钱操作,所有将这两个方法都修改为同步方法.(使用synchronized关键字)。
public class Account {
private String accountNo;
//标识账户中是否有存款的旗标
private boolean flag=
public Account() {
public Account(String accountNo, double balance) {
this.accountNo = accountNo;
this.balance =
public synchronized void draw (double drawAmount){
if(!flag){
this.wait();
System.out.println(Thread.currentThread().getName()+" 取钱:"+drawAmount);
balance=balance-drawA
System.out.println("余额 : "+balance);
//将标识账户是否已有存款的标志设为false
//唤醒其它线程
this.notifyAll();
} catch (Exception e) {
e.printStackTrace();
public synchronized void deposit(double depositAmount){
this.wait();
System.out.println(Thread.currentThread().getName()+"存钱"+depositAmount);
balance=balance+depositA
System.out.println("账户余额为:"+balance);
//唤醒其它线程
this.notifyAll();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
·&接下来创建两个线程类,分别为取钱和存钱线程!
·&取钱线程类:
public class DrawThread implements Runnable {
private double drawA
public DrawThread(Account account, double drawAmount) {
this.account =
this.drawAmount = drawA
public void run() {
for(int i=0;i&100;i++){
account.draw(drawAmount);
·&存钱线程类:
public class depositThread implements Runnable{
private double depositA
public depositThread(Account account, double depositAmount) {
this.account =
this.depositAmount = depositA
public void run() {
for(int i=0;i&100;i++){
account.deposit(depositAmount);
·&最后我们测试一下这个取钱和存钱的操作
public &class TestDraw {
public static void main(String[] args) {
//创建一个账户
Account account=new Account();
new Thread(new DrawThread(account, 800),"取钱者").start();
new Thread(new depositThread(account, 800),"存款者甲").start();
new Thread(new depositThread(account, 800),"存款者乙").start();
new Thread(new depositThread(account, 800),"存款者丙").start();
·&大致的输出结果如下
存款者甲存钱800.0
账户余额为:800.0
取钱者 取钱:800.0
余额 : 0.0
存款者丙存钱800.0
账户余额为:800.0
取钱者 取钱:800.0
余额 : 0.0
存款者甲存钱800.0
账户余额为:800.0
取钱者 取钱:800.0
余额 : 0.0
存款者丙存钱800.0
账户余额为:800.0
取钱者 取钱:800.0
余额 : 0.0
存款者甲存钱800.0
账户余额为:800.0
取钱者 取钱:800.0
余额 : 0.0
存款者丙存钱800.0
账户余额为:800.0
取钱者 取钱:800.0
余额 : 0.0
存款者甲存钱800.0
账户余额为:800.0
取钱者 取钱:800.0
余额 : 0.0
存款者丙存钱800.0
账户余额为:800.0
取钱者 取钱:800.0
余额 : 0.0
存款者甲存钱800.0
账户余额为:800.0
取钱者 取钱:800.0
余额 : 0.0
1.2.3 Lock/Condition机制
·&如何程序不使用synchronized关键字来保持同步,而是直接适用Lock对像来保持同步,则系统中不存在隐式的同步监视器对象,也就不能使用wait()、notify()、notifyAll()来协调线程的运行.
·&当使用LOCK对象保持同步时,Java为我们提供了Condition类来协调线程的运行。关于Condition类,JDK文档里进行了详细的解释.,再次就不啰嗦了。
·&我们就拿Account类进行稍微的修改 一下吧!
import java.util.concurrent.locks.C
import java.util.concurrent.locks.L
import java.util.concurrent.locks.ReentrantL
public class Account {
//显示定义Lock对象
private final Lock lock=new ReentrantLock();
//获得指定Lock对象对应的条件变量
private final &Condition con=lock.newCondition();
private String accountNo;
//标识账户中是否有存款的旗标
private boolean flag=
public Account() {
public Account(String accountNo, double balance) {
this.accountNo = accountNo;
this.balance =
public void draw (double drawAmount){
lock.lock();
if(!flag){
// &&&&&&&&&&&this.wait();
con.await();
System.out.println(Thread.currentThread().getName()+" 取钱:"+drawAmount);
balance=balance-drawA
System.out.println("余额 : "+balance);
//将标识账户是否已有存款的标志设为false
//唤醒其它线程
// &&&&&&&&&&&&&&this.notifyAll();
con.signalAll();
} catch (Exception e) {
e.printStackTrace();
lock.unlock();
public void deposit(double depositAmount){
lock.lock();
// &&&&&&&&&&&&&this.wait();
con.await();
System.out.println(Thread.currentThread().getName()+"存钱"+depositAmount);
balance=balance+depositA
System.out.println("账户余额为:"+balance);
//唤醒其它线程
// &&&&&&&&&&&&&&&this.notifyAll();
con.signalAll();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
lock.unlock();
·&输出结果和上面是一样的!只不过这里显示的使用Lock对像来充当同步监视器,使用Condition对象来暂停指定线程,唤醒指定线程!
1.2.4 管道
管道流是JAVA中线程通讯的常用方式之一,基本流程如下:
创建管道输出流PipedOutputStream pos和管道输入流PipedInputStream pis
将pos和pis匹配,pos.connect(pis);
将pos赋给信息输入线程,pis赋给信息获取线程,就可以实现线程间的通讯了
import java.io.IOE
import java.io.PipedInputS
import java.io.PipedOutputS
public class testPipeConnection {
public static void main(String[] args) {
* 创建管道输出流
PipedOutputStream pos = new PipedOutputStream();
* 创建管道输入流
PipedInputStream pis = new PipedInputStream();
* 将管道输入流与输出流连接 此过程也可通过重载的构造函数来实现
pos.connect(pis);
} catch (IOException e) {
e.printStackTrace();
* 创建生产者线程
Producer p = new Producer(pos);
* 创建消费者线程
Consumer1 c1 = new Consumer1(pis);
* 启动线程
p.start();
c1.start();
* 生产者线程(与一个管道输入流相关联)
class Producer extends Thread {
private PipedOutputS
public Producer(PipedOutputStream pos) {
this.pos =
public void run() {
int i = 0;
while(true)
this.sleep(3000);
pos.write(i);
} catch (Exception e) {
e.printStackTrace();
* 消费者线程(与一个管道输入流相关联)
class Consumer1 extends Thread {
private PipedInputS
public Consumer1(PipedInputStream pis) {
this.pis =
public void run() {
while(true)
System.out.println("consumer1:"+pis.read());
} catch (IOException e) {
e.printStackTrace();
·&程序启动后,就可以看到producer线程往consumer1线程发送数据
consumer1:0
consumer1:1
consumer1:2
consumer1:3
管道流虽然使用起来方便,但是也有一些缺点
管道流只能在两个线程之间传递数据 。线程consumer1和consumer2同时从pis中read数据,当线程producer往管道流中写入一段数据后,每一个时刻只有一个线程能获取到数据,并不是两个线程都能获取到producer发送来的数据,因此一个管道流只能用于两个线程间的通讯。不仅仅是管道流,其他IO方式都是一对一传输。
管道流只能实现单向发送,如果要两个线程之间互通讯,则需要两个管道流 。可以看到上面的例子中,线程producer通过管道流向线程consumer发送数据,如果线程consumer想给线程producer发送数据,则需要新建另一个管道流pos1和pis1,将pos1赋给consumer1,将pis1赋给producer,具体例子本文不再多说。
2 进程与进程间通信
2.1 进程间通信方式
· 管道(Pipe) :管道可用于具有亲缘关系进程间的通信,允许一个进程和另一个与它有共同祖先的进程之间进行通信。
· 命名管道(named pipe) :命名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关系进程间的通信。命名管道在文件系统中有对应的文件名。命名管道通过命令mkfifo或系统调用mkfifo来创建。
· 信号(Signal) :信号是比较复杂的通信方式,用于通知接受进程有某种事件发生,除了用于进程间通信外,进程还可以发送信号给进程本身;Linux除了支持Unix早期信号语义函数sigal外,还支持语义符合Posix.1标准的信号函数sigaction(实际上,该函数是基于BSD的,BSD为了实现可靠信号机制,又能够统一对外接口,用sigaction函数重新实现了signal函数)。
· 消息(Message)队列 :消息队列是消息的链接表,包括Posix消息队列system V消息队列。有足够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的消息。消息队列克服了信号承载信息量少,管道只能承载无格式字节流以及缓冲区大小受限等缺
· 共享内存 :使得多个进程可以访问同一块内存空间,是最快的可用IPC形式。是针对其他通信机制运行效率较低而设计的。往往与其它通信机制,如信号量结合使用,来达到进程间的同步及互斥。
· 内存映射(mapped memory) :内存映射允许任何多个进程间通信,每一个使用该机制的进程通过把一个共享的文件映射到自己的进程地址空间来实现它。
· 信号量(semaphore) :主要作为进程间以及同一进程不同线程之间的同步手段。
· 套接口(Socket) :更为一般的进程间通信机制,可用于不同机器之间的进程间通信。起初是由Unix系统的BSD分支开发出来的,但现在一般可以移植到其它类Unix系统上:linux和System V的变种都支持套接字。
·&&个人介绍
·&&·&&springMVC拦截器和过滤器的区别
·&&·&&excel导出功能如何实现
·&&·&&SpringIOC和AOP,动态代理实现方式
·&&·&&自动装配有哪几种方式,自动装配有什么局限性
在每个bean中都一个autowire=default的默认配置它的含义是:
采用beans和跟标签中的default-autowire="属性值"一样的设置。
不使用自动装配,必须通过ref元素指定依赖,默认设置。
根据属性名自动装配。此选项将检查容器并根据名字查找与属性完全一致的bean,并将其与属性自动装配。例如,在bean定义中将autowire设置为by&name,而该bean包含master属性(同时提供setMaster(..)方法),Spring就会查找名为master的bean定义,并用它来装配给master属性。
如果容器中存在一个与指定属性类型相同的bean,那么将与该属性自动装配。如果存在多个该类型的bean,那么将会抛出异常,并指出不能使用byType方式进行自动装配。若没有找到相匹配的bean,则什么事都不发生,属性也不会被设置。如果你不希望这样,那么可以通过设置dependency-check="objects"让Spring抛出异常。
Constructor
与byType的方式类似,不同之处在于它应用于构造器参数。如果在容器中没有找到与构造器参数类型一致的bean,那么将会抛出异常。
Antodetect
通过bean类的自省机制(introspection)来决定是使用constructor还是byType方式进行自动装配。如果发现默认的构造器,那么将使用byType方式。
byName&和byType
在使用的过程中必须保证bean能够初始化,否则的话会出现bug
如果有默认的无参数的构造器就不需要多余的配置
如果有带有参数的构造器,那在bean的配置中必须配置器初始化的参数&或者在bean中添加无参数的构造器
基本类型不可以装配,精准度&易混乱bean必须可以获得
·&&·&&数据库引擎,Innodb,MyISAM的区别
1.&MySQL默认采用的是MyISAM。
2.&MyISAM不支持事务,而InnoDB支持。InnoDB的AUTOCOMMIT默认是打开的,即每条SQL语句会默认被封装成一个事务,自动提交,这样会影响速度,所以最好是把多条SQL语句显示放在begin和commit之间,组成一个事务去提交。
3.&InnoDB支持数据行锁定,MyISAM不支持行锁定,只支持锁定整个表。即MyISAM同一个表上的读锁和写锁是互斥的,MyISAM并发读写时如果等待队列中既有读请求又有写请求,默认写请求的优先级高,即使读请求先到,所以MyISAM不适合于有大量查询和修改并存的情况,那样查询进程会长时间阻塞。因为MyISAM是锁表,所以某项读操作比较耗时会使其他写进程饿死。
4.&InnoDB支持外键,MyISAM不支持。
5.&InnoDB的主键范围更大,最大是MyISAM的2倍。
6.&InnoDB不支持全文索引,而MyISAM支持。全文索引是指对char、varchar和text中的每个词(停用词除外)建立倒排序索引。MyISAM的全文索引其实没啥用,因为它不支持中文分词,必须由使用者分词后加入空格再写到数据表里,而且少于4个汉字的词会和停用词一样被忽略掉。
7.&MyISAM支持GIS数据,InnoDB不支持。即MyISAM支持以下空间数据对象:Point,Line,Polygon,Surface等。
8.&没有where的count(*)使用MyISAM要比InnoDB快得多。因为MyISAM内置了一个计数器,count(*)时它直接从计数器中读,而InnoDB必须扫描全表。所以在InnoDB上执行count(*)时一般要伴随where,且where中要包含主键以外的索引列。为什么这里特别强调“主键以外”?因为InnoDB中primary index是和raw data存放在一起的,而secondary index则是单独存放,然后有个指针指向primary key。所以只是count(*)的话使用secondary index扫描更快,而primary key则主要在扫描索引同时要返回raw data时的作用较大。
·&&·&&索引实现方式,B+树有什么特点,B树和B+数的区别,B+树的实现方式
·&&·&&索引的最左配原则
·&&·&&HashMap和HashSet的区别,HashMap是有序的吗
·&&·&&LinkedHashMap,保证什么有序,底层实现。
·&&·&&java多线程的方式,FutureTask CallAble介绍,CallAble和Runnable的区别
·&&·&&线程池
·&&·&&类的加载过程,双亲委派机制
上午交叉面,下午已回绝。四面挂,心痛。分享面经,为后面校招攒人品。
一面:(8月1号上午:电话面试:80分32秒)
1.自我介绍?
2.做过哪些项目?项目中遇到哪些难点,你是怎样解决的?单点登录系统说一下?分布式缓存的使用场景?(说好的基础呢,上来就是项目,毫无准备,导致好多东西都记不起来了。面试官还说“那你说一个你记得的项目”,手动无奈。。。)
分布式缓存的典型应用场景可分为以下几类:
1)页面缓存.用来缓存Web页面的内容片段,包括HTML、CSS和图片等,多应用于社交网站等;
2)应用对象缓存.缓存系统作为ORM框架的二级缓存对外提供服务,目的是减轻数据库的负载压力,加速应用访问;
3)状态缓存.缓存包括Session会话状态及应用横向扩展时的状态数据等,这类数据一般是难以恢复的,对可用性要求较高,多应用于高可用集群;
4)并行处理.通常涉及大量中间计算结果需要共享;
5)事件处理.分布式缓存提供了针对事件流的连续查询(continuous query)处理技术,满足实时性需求;
6)极限事务处理.分布式缓存为事务型应用提供高吞吐率、低延时的解决方案,支持高并发事务请求处理,多应用于铁路、金融服务和电信等领域.
3.你实习的时候JDK用的是那个版本,这个版本有什么新的特性?
Jdk7的新特性:
1.对集合类的语言支持;(??)
2.自动资源管理;
3.改进的通用实例创建类型推断;(??)
4.数字字面量下划线支持;(√)
5.switch中使用string;(√)
JSR292 的实现增加了一个 InvokeDynamic 的字节码指令来支持动态类型语言,使得在把源代码编译成字节码时并不需要确定方法的签名,即方法参数的类型和返回类型。当运行时执行 InvokeDynamic 指令时,JVM 会通过新的动态链接机制 Method Handles,寻找到真实的方法。
ClassLoader 新增 API
为了防止自定义多线程ClassLoad产生的死锁问题,java.lang.ClassLoader类增加了以下API。
4.G1回收器和其他回收器有什么区别?
并发与并行,部分代&自己就可以,局部复制全局标记整理堆&4G会比较好。
Java 8及G1回收器
Java 8 update 20所引入的一个很棒的优化就是G1回收器中的字符串去重(String deduplication)。由于字符串(包括它们内部的char[]数组)占用了大多数的堆空间,这项新的优化旨在使得G1回收器能识别出堆中那些重复出现的字符串并将它们指向同一个内部的char[]数组,以避免同一个字符串的多份拷贝,那样堆的使用效率会变得很低。你可以使用-XX:+UseStringDeduplication这个JVM参数来试一下这个特性。
Java 8及持久代
Java 8中最大的改变就是持久代的移除,它原本是用来给类元数据,驻留字符串,静态变量来分配空间的。这在以前都是需要开发人员来针对那些会加载大量类的应用来专门进行堆比例的优化及调整。许多年来都是如此,这也正是许多OutOfMemory异常的根源,因此由JVM来接管它真是再好不过了。即便如此,它本身并不会减少开发人员将应用解耦到不同的JVM中的可能性。
每个回收器都有许多不同的开关和选项来进行调优,这可能会增加吞吐量,也可能会减少,这取决于你的应用的具体的行为了。在下一篇文章中我们会深入讲解配置这些算法的关键策略。
5.垃圾回收为什么会停顿?哪些对象可能作为GCRoots?
虚拟机栈中引用的对象&方法区(静态属性,常量引用的对象)本地方法栈中引用的对象。
6.垃圾回收分代收集算法?为什么会有两个Survivor区?new一个对象会保存在哪里?
Survivor的存在意义,就是减少被送到老年代的对象,进而减少Full GC的发生,Survivor的预筛选保证,只有经历16次Minor GC还能在新生代中存活的对象,才会被送到老年代。
设置两个Survivor区最大的好处就是解决了碎片化
7.Java内存模型?volatile关键字,使用场景?原子性的理解?先行发生原则?
Java内存模型中规定了所有的变量都存储在主内存中,每条线程还有自己的工作内存(可以与前面将的处理器的高速缓存类比),线程的工作内存中保存了该线程使用到的变量到主内存副本拷贝,线程对变量的所有操作(读取、赋值)都必须在工作内存中进行,而不能直接读写主内存中的变量。
·&lock(锁定):作用于主内存的变量,把一个变量标识为一条线程独占状态。
·&unlock(解锁):作用于主内存变量,把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定。
·&read(读取):作用于主内存变量,把一个变量值从主内存传输到线程的工作内存中,以便随后的load动作使用
·&load(载入):作用于工作内存的变量,它把read操作从主内存中得到的变量值放入工作内存的变量副本中。
·&use(使用):作用于工作内存的变量,把工作内存中的一个变量值传递给执行引擎,每当虚拟机遇到一个需要使用变量的值的字节码指令时将会执行这个操作。
·&assign(赋值):作用于工作内存的变量,它把一个从执行引擎接收到的值赋值给工作内存的变量,每当虚拟机遇到一个给变量赋值的字节码指令时执行这个操作。
·&store(存储):作用于工作内存的变量,把工作内存中的一个变量的值传送到主内存中,以便随后的write的操作。
·&write(写入):作用于主内存的变量,它把store操作从工作内存中一个变量的值传送到主内存的变量中。
如果要把一个变量从主内存中复制到工作内存,就需要按顺寻地执行read和load操作,如果把变量从工作内存中同步回主内存中,就要按顺序地执行store和write操作。Java内存模型只要求上述操作必须按顺序执行,而没有保证必须是连续执行。也就是read和load之间,store和write之间是可以插入其他指令的,如对主内存中的变量a、b进行访问时,可能的顺序是read a,read b,load b,load a。Java内存模型还规定了在执行上述八种基本操作时,必须满足如下规则:
·&不允许read和load、store和write操作之一单独出现
·&不允许一个线程丢弃它的最近assign的操作,即变量在工作内存中改变了之后必须同步到主内存中。
·&不允许一个线程无原因地(没有发生过任何assign操作)把数据从工作内存同步回主内存中。
·&一个新的变量只能在主内存中诞生,不允许在工作内存中直接使用一个未被初始化(load或assign)的变量。即就是对一个变量实施use和store操作之前,必须先执行过了assign和load操作。
·&一个变量在同一时刻只允许一条线程对其进行lock操作,lock和unlock必须成对出现
·&如果对一个变量执行lock操作,将会清空工作内存中此变量的值,在执行引擎使用这个变量前需要重新执行load或assign操作初始化变量的值
·&如果一个变量事先没有被lock操作锁定,则不允许对它执行unlock操作;也不允许去unlock一个被其他线程锁定的变量。
·&对一个变量执行unlock操作之前,必须先把此变量同步到主内存中(执行store和write操作)。
Volatile有五个使用场景(参考的文章):
1.作为状态标志
2.一次性安全发布
3.独立观察
4.volatile bean模式
5.开销较低的读写锁策略
Java内存模型中存在的天然的先行发生关系:
1. 程序次序规则:同一个线程内,按照代码出现的顺序,前面的代码先行于后面的代码,准确的说是控制流顺序,因为要考虑到分支和循环结构。
2. 管程锁定规则:一个unlock操作先行发生于后面(时间上)对同一个锁的lock操作。
3. volatile变量规则:对一个volatile变量的写操作先行发生于后面(时间上)对这个变量的读操作。
4. 线程启动规则:Thread的start( )方法先行发生于这个线程的每一个操作。
5. 线程终止规则:线程的所有操作都先行于此线程的终止检测。可以通过Thread.join( )方法结束、Thread.isAlive( )的返回值等手段检测线程的终止。
6. 线程中断规则:对线程interrupt( )方法的调用先行发生于被中断线程的代码检测到中断事件的发生,可以通过Thread.interrupt( )方法检测线程是否中断
7. 对象终结规则:一个对象的初始化完成先行于发生它的finalize()方法的开始。
8. 传递性:如果操作A先行于操作B,操作B先行于操作C,那么操作A先行于操作C。
8.场景题:现在有三个线程,同时start,用什么方法可以保证线程执行的顺序,线程一执行完线程二执行,线程二执行完线程三执行?
package com.wenjie.threadD
public class JionTest {
public static void main(String[] args) {
final Thread t1 = new Thread(new Runnable() {
public void run() {
// TODO Auto-generated method stub
System.out.println("t1");
final Thread t2 = new Thread(new Runnable() {
public void run() {
// TODO Auto-generated method stub
t1.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("t2");
final Thread t3 = new Thread(new Runnable() {
public void run() {
// TODO Auto-generated method stub
t2.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("t3");
t2.start();
t3.start();
t1.start();
9.你是怎么理解线程安全的?HashMap是线程安全的么?如果多个线程同时修改HashMap时会发生什么情况?
异常concurrentmodeex
10.ConcurrentHashMap底层原理?每个版本的实现上有什么区别?
11.静态代理和动态代理的区别?动态代理是怎么实现的?
12.深拷贝和浅拷贝的区别?
13.你做过hadoop的项目,为什么要用hadoop?你们处理的文件是什么格式的?写了几个mapper几个reducer?
Hbase,json
14.zookeeper你们用了几台,用来干什么的?一般情况下都是奇数台,那么如果一台挂了,偶数台如何实现master选举?zookeeper的两种启动模式?
15.TCP首部?TCP为什么是可靠的?三次握手四次挥手?
TCP提供一种面向连接的、可靠的字节流服务。
面向连接:意味着两个使用TCP的应用(通常是一个客户和一个服务器)在彼此交换数据之前必须先建立一个TCP连接。在一个TCP连接中,仅有两方进行彼此通信。广播和多播不能用于TCP。
TCP通过下列方式来提供可靠性:
1、应用数据被分割成TCP认为最适合发送的数据块。这和UDP完全不同,应用程序产生的数据报长度将保持不变。 (将数据截断为合理的长度)
2、当TCP发出一个段后,它启动一个定时器,等待目的端确认收到这个报文段。如果不能及时收到一个确认,将重发这个报文段。
(超时重发)
3、当TCP收到发自TCP连接另一端的数据,它将发送一个确认。这个确认不是立即发送,通常将推迟几分之一秒 。 (对于收到的请求,给出确认响应) (之所以推迟,可能是要对包做完整校验)
4、TCP将保持它首部和数据的检验和。这是一个端到端的检验和,目的是检测数据在传输过程中的任何变化。如果收到段的检验和有差错,TCP将丢弃这个报文段和不确认收到此报文段。 (校验出包有错,丢弃报文段,不给出响应,TCP发送数据端,超时时会重发数据)
5、既然TCP报文段作为IP数据报来传输,而IP数据报的到达可能会失序,因此TCP报文段的到达也可能会失序。如果必要,TCP将对收到的数据进行重新排序,将收到的数据以正确的顺序交给应用层。 (对失序数据进行重新排序,然后才交给应用层)
6、既然IP数据报会发生重复,TCP的接收端必须丢弃重复的数据。(对于重复数据,能够丢弃重复数据)
7、TCP还能提供流量控制。TCP连接的每一方都有固定大小的缓冲空间。TCP的接收端只允许另一端发送接收端缓冲区所能接纳的数据。这将防止较快主机致使较慢主机的缓冲区溢出。(TCP可以进行流量控制,防止较快主机致使较慢主机的缓冲区溢出)TCP使用的流量控制协议是可变大小的滑动窗口协议。
字节流服务::
两个应用程序通过TCP连接交换8bit字节构成的字节流。TCP不在字节流中插入记录标识符。我们将这称为字节流服务(bytestreamservice)。
TCP对字节流的内容不作任何解释:: TCP对字节流的内容不作任何解释。TCP不知道传输的数据字节流是二进制数据,还是ASCII字符、EBCDIC字符或者其他类型数据。对字节流的解释由TCP连接双方的应用层解释。
17.你平时喜欢做什么?看过哪些书?最近在看什么书?(这里有个段子,我:最近在看《HTTP权威指南》。面试官:什么?HTTP潜规则?我:???)
柯南&东野圭吾
舞蹈&运动电影
二面:(8月2号晚上:视频面试:47分钟)
1.你那边怎么有点黑啊?(我靠,我也想说啊,暑假寝室集中供电,然而我们寝室没有电。发面经也不忘吐槽学校,简直坑啊。。。抱着台灯瑟瑟发抖。。。)
2.现在在哪里实习?实习主要做些什么?
3.说一下Java里面你最感兴趣的一个部分?
4.熟悉Java的哪些框架?用了Spring的哪些东西?Spring现在最新的版本是多少?
5.讲一下MVC设计模式,有什么框架用到了这个模式?spring
6.场景题:一个Controller调用两个Service,这两Service又都分别调用两个Dao,问其中用到了几个数据库连接池的连接?
7.安全方面:如何防止SQL注入?如何防止用户删除其他用户的信息?表单提交可以跨域么?自己写的接口如何防止被其他人恶意调用?
貌似浏览器也不允许js修改已经存在的header,只能增加自定义header:
防止被恶意调用的话,可以做请求限制,第一次请求返回一个随机数,下次请求把随机数带过来,返回时再返回一个随机数
8.zookeeper偶数选举问题?(感觉很重视zookeeper啊)
9.hadoop为什么要将文件分块并且复制三份,复制两份不行么?这样不浪费空间么?namenode脑裂问题?zookeeper如何管理全局配置文件?你们的Hadoop项目用到了几台机器,每个机器的作用?
10.Servlet是线程安全的么?
11.创建一个对象的详细过程?其中发生了些什么?
12.Java NIO你了解么?讲一讲你最熟悉的部分?
13.你在生活中有没有遇到什么神奇的事情,可以分享一下么?比如洒水车为什么老是在阴天或者快下雨的时候洒水?还有我和我老婆经常吵,阳台的花是早上浇好呢,还是晚上浇好呢?(我靠,这是什么套路)
14.你认为你身边的同学怎么样?如果你正在打游戏,你想让同学帮忙带瓶水,你觉得有多少人会帮你带?(这又是什么套路?让我去送水?)
15.你还有什么想问的?
三面:(HR面,8月4号下午:视频面试:22分钟)
1.7岁一个阶段,说一说每一个阶段对你影响最大的一个人或事?
2.说一下你大学阶段做了些什么?
3.你感觉你前两个面试官怎么样?
4.春招的时候为什么没有去bat实习?
5.你当初准备暑期实习的话,是想学到些什么?现在感觉自己有哪些进步?
6.你还有什么想问的?(当然是万能的培养计划和晋升机制)
四面:(交叉面,8月16号上午:电话面试:30分钟)
1.自我介绍?
2.说一下最能代表你技术水平的项目吧?
3.maven如何进行依赖管理,如何解决依赖冲突?
为什么会出现依赖冲突
首先要说明Maven的依赖管理,具体的可以参考这边 这篇文章,maven在依赖冲管理中有一下几个原则。
1.&依赖是使用Maven坐标来定位的,而Maven坐标主要由GAV(groupId, artifactId, version)构成。如果两个相同的依赖包,如果groupId, artifactId, version不同,那么maven也认为这两个是不同的。
2.&依赖会传递,A依赖了B,B依赖了C,那么A的依赖中就会出现B和C。
3.&Maven对同一个groupId, artifactId的冲突仲裁,不是以version越大越保留,而是依赖路径越短越优先,然后进行保留。
4.&依赖的scope会影响依赖的影响范围。
当出现了依赖的时候如何快速定位冲突原因
但出现了冲突的时候,比如系统出现了NoSuchMethodError, 很有可能是你系统中出现了依赖冲突。出现冲突以后,可以按以下的步骤执行
1.确定出了问题的jar包名称。通常可以在eclipse中查找冲突的类有在哪些依赖包里面出现了。并确定实际要使用的是那个包,冲突的包有哪些。
2.通过mvn dependency:tree& && tree.txt导出全部的依赖。
3.在导出的依赖文件中,查找问题相关的jar。确定这些jar是如何被依赖进来的,是直接依赖的还是通过传递依赖引入的。
4.找到相互冲突的并需要排除的依赖的顶级依赖,并分析冲突的原因,冲突的原因可能是以下几种:
·&同一个jar包但groupId, artifactId不同,这种冲突只能通过设定依赖的&exclusions&来进行排除
·&需要的版本jar包依赖路径较长,这种冲突可以把想要版本的依赖直接什么在依赖中,这样路径就最短了优先级最高。
5.最后可以通过打包mvn install来确认打出来的war包中是否有被排除的依赖。
4.maven的源和插件了解哪些?maven的生命周期?
5.如何保证分布式缓存的一致性?分布式session实现?
6.spring的bean的创建时机?依赖注入的时机?
7.你们的图片时怎么存储的,对应在数据库中时如何保存图片的信息的?
最好是二进制或者项目中,直接保存相对路径
8.单点登录系统的实现?
9.项目中用到的JDK的哪些特性?
10.java8流式迭代的好处?
11.多线程如何在多个CPU上分布?线程调度算法有哪些?
12.线程调度和进程调度的区别?
13.项目中用到了哪些集合类?
14.说一下TreeMap的实现原理?红黑树的性质?红黑树遍历方式有哪些?如果key冲突如何解决?setColor()方法在什么时候用?什么时候会进行旋转和颜色转换?后者覆盖前者&保持唯一性
15.你有什么想问的?
时隔两年,再一次的面临离职找工作,这一次换工作有些许的不舍,也有些许的无奈。个人所在的技术团队不错,两年时间成长了很多,也很不舍这个团队。但是,由于公司的某些原因和对于自身未来发展的综合考虑,又不得不得离去,去寻找更合适的地方成长和发展。相比于两年前,现在找工作没有那么的着急,也没有那么的迫切,也没有特别想去的公司,反正去大厂互联网公司基本都是加班加点的。也许,这是工作三年的我即将面临的一个坎吧。对于未来的选择和考虑,对于未来的恐惧吧。也许我是杞人忧天,也许是上天注定我将去某一家公司,不管怎样,坚持做最好的自己!不停进步,不停成长!
下面将最近面试遇到的一些题目进行汇总如下,希望对现在正在找工作的同学和现在面临毕业找工作的同学有所帮助。
1、常用设计模式
单例模式:懒汉式、饿汉式、双重校验锁、静态加载,内部类加载、枚举类加载。保证一个类仅有一个实例,并提供一个访问它的全局访问点。
代理模式:动态代理和静态代理,什么时候使用动态代理。
适配器模式:将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
装饰者模式:动态给类加功能。
观察者模式:有时被称作发布/订阅模式,观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。
策略模式:定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。
外观模式:为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
命令模式:将一个请求封装成一个对象,从而使您可以用不同的请求对客户进行参数化。
创建者模式:将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。
抽象工厂模式:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
2、基础知识
基本类型哪些,所占字节和范围
Set、List、Map的区别和联系
什么时候使用HashMap
什么时候使用LinkedHashMap、ConcurrentHashMap、WeakHashMap
哪些集合类是线程安全的
为什么Set、List、Map不实现Cloneable和Serializable接口
ConcurrentHashMap的实现,1.7和1.8的实现
Arrays.sort的实现
什么时候使用CopyOnArrayList
volatile的使用
Synchronied的使用
ReentrantLock的实现以及和Synchronied的区别
CAS的实现原理以及问题
AQS的实现原理
接口和抽象类的区别,什么时候使用
类加载机制的步骤,每一步做了什么,static和final修改的成员变量的加载时机
双亲委派模型
反射机制:反射动态擦除泛型、反射动态调用方法等
动态绑定:父类引用指向子类对象
JVM内存管理机制:有哪些区域,每个区域做了什么
JVM垃圾回收机制:垃圾回收算法 垃圾回收器 垃圾回收策略
jvm参数的设置和jvm调优
什么情况产生年轻代内存溢出、什么情况产生年老代内存溢出
内部类:静态内部类和匿名内部类的使用和区别
redis和memcached:什么时候选择redis,什么时候选择memcached,内存模型和存储策略是什么样的
的基本操作主从一致性维护
mysql的优化策略有哪些
mysql索引的实现B+树的实现原理
什么情况索引不会命中,会造成全表扫描
java中bio nio aio的区别和联系
为什么bio是阻塞的nio是非阻塞的nio的模型是什么样的
java io的整体和使用的设计模式
Reactor模型和Proactor模型
http请求报文结构和内容
http三次握手和四次挥手
rpc相关:如何设计一个rpc框架,从io模型 传输协议 序列化方式综合考虑
linux命令 统计,排序,前几问题等
StringBuff和StringBuilder的实现,底层实现是通过byte数据,外加数组的拷贝来实现的
cas操作的使用
内存缓存和数据库的一致性同步实现
微服务的优缺点
线程池的参数问题
ip问题 如何判断ip是否在多个ip段中
判断数组两个中任意两个数之和是否为给定的值
乐观锁和悲观锁的实现
synchronized实现原理
你在项目中遇到的困难和怎么解决的
你在项目中完成的比较出色的亮点
消息队列广播模式和发布/订阅模式的区别
生产者消费者代码实现
死锁代码实现
线程池:参数,每个参数的作用,几种不同线程池的比较,阻塞队列的使用,拒绝策略
Future和ListenableFuture异步回调相关
算法相关:判断能否从数组中找出两个数字和为给定值,随机生成1~10000不重复并放入数组,求数组的子数组的最大和,二分查找算法的实现及其时间复杂计算
算法:常用排序算法,二分查找,链表相关,数组相关,字符串相关,树相关等
常见序列化协议及其优缺点
memcached内存原理,为什么是基于块的存储
搭建一个rpc需要准备什么
如果线上服务器频繁地出现full gc,如何去排查
如果某一时刻线上机器突然量变得很大,服务扛不住了,怎么解决
LRU算法的实现
LinkedHashMap实现LRU
定义栈的数据结构,请在该类型中实现一个能够找到栈最小元素的min函数
海量数据处理的解决思路
reactor模型的演变
阻塞、非阻塞、同步、异步区别
Collection的子接口
jvm调优相关
zookeeper相关,节点类型,如何实现服务发现和服务注册
nginx负载均衡相关,让你去实现负载均衡,该怎么实现
linux命令,awk、cat、sort、cut、grep、uniq、wc、top等
压力测试相关,怎么分析,单接口压测和多情况下的压测
你觉得你的优点是什么,你的缺点是什么,为什么我们要录用你
Spring mvc的实现原理
netty底层实现,IO模型,ChannelPipeline的实现和原理
缓存的设计和优化
缓存和数据库一致性同步解决方案
你所在项目的系统架构,谈谈整体实现
消息队列的使用场景
ActiveMQ、RabbitMQ、Kafka的区别
JVM内存分配策略和垃圾回收时机
JVM垃圾回收策略和对象的实际生命周期
对象是如何在堆中分配的
full gc触发的场景,线上如果一直full gc怎么排查
如何防止接口被恶意攻击
线上某一台服务器出现问题,如何实际操作去解决
线上接口最大的QPS以及如何评估服务器可承受的最大请求数
内存缓存的使用场景和优缺点
怎么防止线上接口被恶意刷
怎么防止线上接口被攻击
栈帧的结构
transient关键字的使用
以上内容为近期的面试总结。后续如有新的内容,会持续更新。
hashMap可以key为空或者value为空吗?可以同时为空吗?
HashSet有什么特点?
HashMap底层是怎么实现的?
1.6:数组+链表
1.8:数组+链表/红黑树
为什么要二次hash?谈谈扩容|什么时候扩容?
HashMap与Hashtable有什么区别吗?
Hashtable加同步锁有什么问题?能不能有更好的实现方式?
ConcurrentHashMap底层怎么实现的?怎么保证同步的(CAS)?
如果前面的,你都答出来了?
什么是CAS?它synchronized有什么区别?
谈谈synchronized?
能谈一下volatile吗?
6、JVM连环炮+并发编程?
1、谈谈内存区域?
堆、栈、方法区、(程序计算器、本地方法栈 )|可以不谈
2、堆、栈、方法区分别有什么用?存储什么内容?
3、能谈谈堆吗?
新生代、老年代
4、怎么判断对象不可用?
5、能谈一下GC策略吗?它是怎么回收不可用对象的?
标记-清除,复制、标记-整理、分代。
6、能谈一下垃圾回收器吗?(暂无碰见问的)
7、对象怎么分配的?
1、谈一下类加载过程?
2、谈一下双亲委派机制?
1、谈一下Java内存模型
2、谈一下Synchronized、volatile?
2、谈一下AQS、CountDownLatch、ReentrantLock?(暂时还没有人问)
3、谈一下ThreadLocal?
4、谈一下CAS?
5、谈一下线程池原理?
二、设计模式
1、谈一下六种设计原则?开闭原则什么意思?里氏XX是什么意思?
2、写一个单例模式?后续自己扩展各种的优缺点?
3、谈一个你熟悉的设计模式?
1、设计一个高效的缓存?
2、谈谈LRU算法?(解决高效的缓存)
三、架构思想、高并发、大数据量解决方案。
1、一个很大的日记文件,统计出访问排行?
2、mapreduce思想?谈谈shuffle?
1、unordered_map的实现原理。。很具体的描述
2、单链表多路归并排序
3、LRU cache的实现,插入、查找、删除时间复杂度不能超过O(1)
有一个场景,现在cache满了,需要淘汰频率最低的那个
更新:0824华为
关于HTTP请求GET和POST的区别
1.GET提交,请求的数据会附在URL之后(就是把数据放置在HTTP协议头<request-line>中),以?分割URL和传输数据,多个参数用&连接;例如:login.action?name=hyddd&password=idontknow&verify=%E4%BD%A0 %E5%A5%BD。如果数据是英文字母/数字,原样发送,如果是空格,转换为+,如果是中文/其他字符,则直接把字符串用BASE64加密,得出如:%E4%BD%A0%E5%A5%BD,其中%XX中的XX为该符号以16进制表示的ASCII。
POST提交:把提交的数据放置在是HTTP包的包体<request-body>中。上文示例中红色字体标明的就是实际的传输数据
因此,GET提交的数据会在地址栏中显示出来,而POST提交,地址栏不会改变
2.传输数据的大小:
首先声明,HTTP协议没有对传输的数据大小进行限制,HTTP协议规范也没有对URL长度进行限制。而在实际开发中存在的限制主要有:
GET:特定浏览器和服务器对URL长度有限制,例如IE对URL长度的限制是2083字节(2K+35)。对于其他浏览器,如Netscape、FireFox等,理论上没有长度限制,其限制取决于操作系统的支持。
因此对于GET提交时,传输数据就会受到URL长度的限制。
POST:由于不是通过URL传值,理论上数据不受限。但实际各个WEB服务器会规定对post提交数据大小进行限制,Apache、IIS6都有各自的配置。
3.安全性:
POST的安全性要比GET的安全性高。注意:这里所说的安全性和上面GET提到的“安全”不是同个概念。上面“安全”的含义仅仅是不作数据修改,而这里安全的含义是真正的Security的含义,比如:通过GET提交数据,用户名和密码将明文出现在URL上,因为(1)登录页面有可能被浏览器缓存,(2)其他人查看浏览器的历史纪录,那么别人就可以拿到你的账号和密码了,
Http协议:一个HTTP请求报文由请求行(request line)、请求头部(header)、空行和请求数据4个部分组成,下图给出了请求报文的一般格式。
请求行由请求方法字段、URL字段和HTTP协议版本字段3个字段组成,它们用空格分隔。例如,GET /index.html HTTP/1.1。
请求头部由关键字/值对组成,每行一对,关键字和值用英文冒号“:”分隔。请求头部通知服务器有关于客户端请求的信息,典型的请求头有:
User-Agent:产生请求的浏览器类型。
Accept:客户端可识别的内容类型列表。
Host:请求的主机名,允许多个域名同处一个IP地址,即虚拟主机。
HTTP响应也由三个部分组成,分别是:状态行、消息报头、响应正文。
HTTP:是互联网上应用最为广泛的一种网络协议,是一个客户端和服务器端请求和应答的标准(TCP),用于从WWW服务器传输超文本到本地浏览器的传输协议,它可以使浏览器更加高效,使网络传输减少。
HTTPS:是以安全为目标的HTTP通道,简单讲是HTTP的安全版,即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL。
HTTPS协议的主要作用可以分为两种:一种是建立一个信息安全通道,来保证数据传输的安全;另一种就是确认网站的真实性。
HTTPS和HTTP的区别主要如下:
1、https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。
2、http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
3、http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
4、http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。
对称密码加解密,非对称密码加解密。
事务隔离级别和实现方式。
反射:固化框架层的,业务层实际上用不太到。JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
遇到问题:分布式加锁问题:
memcached分布式锁:1、实现原理:
memcached带有add函数,利用add函数的特性即可实现分布式锁。add和set的区别在于:如果多线程并发set,则每个set都会成功,但最后存储的值以最后的set的线程为准。而add的话则相反,add会添加第一个到达的值,并返回true,后续的添加则都会返回false。利用该点即可很轻松地实现分布式锁。
并发高效。
效率对库依赖比较重,重量级
(1)memcached采用列入LRU置换策略,所以如果内存不够,可能导致缓存中的锁信息丢失。
(2)memcached无法持久化,一旦重启,将导致信息丢失。
Redis:redis分布式锁即可以结合zk分布式锁锁高度安全和memcached并发场景下效率很好的优点,可以利用jedis客户端实现。
URL到页面相应的全过程:
浏览器缓存etc缓存 路由缓存 服务提供商缓存 递归到根dns,请求连接TCP。发送报文,恢复
Spring AOP开发用到了那些部分?
==一般只用到了基本数据类型比较
1、equals方法用于比较对象的内容是否相等(覆盖以后)
2、hashcode方法只有在集合中用到
3、当覆盖了equals方法时,比较对象是否相等将通过覆盖后的equals方法进行比较(判断对象的内容是否相等)。
4、将对象放入到集合中时,首先判断要放入对象的hashcode值与集合中的任意一个元素的hashcode值是否相等,如果不相等直接将该对象放入集合中。如果hashcode值相等,然后再通过equals方法判断要放入对象与集合中的任意一个对象是否相等,如果equals判断不相等,直接将该元素放入到集合中,否则不放入。
作者:Xoper.ducky
来源:牛客网
1.&九种基本数据类型的大小,以及他们的封装类。
大小(字节)
\u0000(null)
2. Switch能否用string做参数?
3. equals与==的区别。
4. Object有哪些公用方法?
Wait notify notifyall clone equels getclass
5.&Java的四种引用,强弱软虚,用到的场景。
6.&Hashcode的作用。
7. ArrayList、LinkedList、Vector的区别。
8. String、StringBuffer与StringBuilder的区别。
9. Map、Set、List、Queue、Stack的特点与用法。
10. HashMap和HashTable的区别。
11. HashMap和ConcurrentHashMap的区别,HashMap的底层源码。
12. TreeMap、HashMap、LindedHashMap的区别。
13. Collection包结构,与Collections的区别。
14. try&catch&finally,try里有return,finally还执行么?
15. Excption与Error包结构。OOM你遇到过哪些情况,SOF你遇到过哪些情况。
16. Java面向对象的三个特征与含义。
17. Override和Overload的含义去区别。
18. Interface与abstract类的区别。
19. Static&class&与non&static&class的区别。
20. java多态的实现原理。
同一操作不同结果,前期绑定后期绑定
21.实现多线程的两种方法:Thread与Runable。Call
22.线程同步的方法:sychronized、lock、reentrantLock等。
23.锁的等级:方法锁、对象锁、类锁。
24.写出生产者消费者模式。
25. ThreadLocal的设计理念与作用。Thread ThreadLocal-&ThreadLocalMap
26. ThreadPool用法与优势。
27. Concurrent包里的其他东西:ArrayBlockingQueue、CountDownLatch等等。
28. wait()和sleep()的区别。
29. foreach与正常for循环效率对比。
30. Java&IO与NIO。
31.反射的作用于原理。
32.泛型常用特点,List&String&能否转为List&Object&。
33.解析XML的几种方式的原理与特点:DOM、SAX、PULL。
34. Java与C++对比。
35. Java1.7与1.8新特性。
36.设计模式:单例、工厂、适配器、责任链、观察者等等。
37. JNI的使用。
Java里有很多很杂的东西,有时候需要你阅读源码,大多数可能书里面讲的不是太清楚,需要你在网上寻找答案。
推荐书籍:《java核心技术卷I》《Thinking&in&java》《java并发编程》《effictive&java》《大话设计模式》
1.内存模型以及分区,需要详细到每个区放什么。
2.堆里面的分区:Eden,survival&from&to,老年代,各自的特点。
3.对象创建方法,对象的内存分配,对象的访问定位。
4. GC的两种判定方法:引用计数与引用链。
5. GC的三种收集方法:标记清除、标记整理、复制算法的原理与特点,分别用在什么地方,如果让你优化收集方法,有什么思路?
6. GC收集器有哪些?CMS收集器与G1收集器的特点。
7. Minor&GC与Full&GC分别在什么时候发生?
8.几种常用的内存调试工具:jmap、jstack、jconsole。
9.类加载的五个过程:加载、验证、准备、解析、初始化。
10.双亲委派模型:Bootstrap&ClassLoader、Extension&ClassLoader、ApplicationClassLoader。
11.分派:静态分派与动态分派。
JVM过去过来就问了这么些问题,没怎么变,内存模型和GC算法这块问得比较多,可以在网上多找几篇博客来看看。
推荐书籍:《深入理解java虚拟机》
1.进程和线程的区别。
2.死锁的必要条件,怎么处理死锁。
3. Window内存管理方式:段存储,页存储,段页存储。
4.进程的几种状态。
5. IPC几种通信方式。
6.什么是虚拟内存。
7.虚拟地址、逻辑地址、线性地址、物理地址的区别。
因为是做android的这一块问得比较少一点,还有可能上我简历上没有写操作系统的原因。
推荐书籍:《深入理解现代操作系统》
1. OSI与TCP/IP各层的结构与功能,都有哪些协议。
2. TCP与UDP的区别。
3. TCP报文结构。
4. TCP的三次握手与四次挥手过程,各个状态名称与含义,TIMEWAIT的作用。
5. TCP拥塞控制。
6. TCP滑动窗口与回退N针协议。
7. Http的报文结构。
8. Http的状态码含义。
9. Http&request的几种类型。
10. Http1.1和Http1.0的区别
11. Http怎么处理长连接。
12. Cookie与Session的作用于原理。
13.电脑上访问一个网页,整个过程是怎么样的:DNS、HTTP、TCP、OSPF、IP、ARP。
14. Ping的整个过程。ICMP报文是什么。
15. C/S模式下使用socket通信,几个关键函数。
16. IP地址分类。
17.路由器与交换机区别。
网络其实大体分为两块,一个TCP协议,一个HTTP协议,只要把这两块以及相关协议搞清楚,一般问题不大。
推荐书籍:《TCP/IP协议族》
数据结构与算法
1.链表与数组。
2.队列和栈,出栈与入栈。
3.链表的删除、插入、反向。
4.字符串操作。
5. Hash表的hash函数,冲突解决方法有哪些。
6.各种排序:冒泡、选择、插入、希尔、归并、快排、堆排、桶排、基数的原理、平均时间复杂度、最坏时间复杂度、空间复杂度、是否稳定。
7.快排的partition函数与归并的Merge函数。
8.对冒泡与快排的改进。
9.二分查找,与变种二分查找。
10.二叉树、B+树、AVL树、红黑树、哈夫曼树。
11.二叉树的前中后续遍历:递归与非递归写法,层序遍历算法。
12.图的BFS与DFS算法,最小生成树prim算法与最短路径Dijkstra算法。
13. KMP算法。
14.排列组合问题。
15.动态规划、贪心算法、分治算法。(一般不会问到)
16.大数据处理:类似10亿条数据找出最大的1000个数.........等等
算法的话其实是个重点,因为最后都是要你写代码,所以算法还是需要花不少时间准备,这里有太多算法题,写不全,我的建议是没事多在OJ上刷刷题(牛客网、leetcode等),剑指offer上的算法要能理解并自己写出来,编程之美也推荐看一看。
推荐书籍:《大话数据结构》《剑指offer》《编程之美》
以下是我常问的几个问题,如果需要可以参考:
1.贵公司一向以XXX著称,能不能说明一下公司这方面的特点?
2.贵公司XXX业务发展很好,这是公司发展的重点么?
3.对技术和业务怎么看?
4.贵公司一般的团队是多大,几个人负责一个产品或者业务?
5.贵公司的开发中是否会使用到一些最新技术?
6.对新人有没有什么培训,会不会安排导师?
7.对Full&Stack怎么看?
8.你觉得我有哪些需要提高的地方?
网易小袁兵总结:
1&java&concurrent包下有哪些类,了解哪些锁
2&hashmap和concurrenthashmap有什么区别?各自的机制是什么样的?hashmap如何解决链表过长?红黑树有哪些特性?
·&&&&&&*&每个结点要么是“红色”,要么是“黑色”(后面将说明)
·&&&&&&*&所有的叶结点都是空结点,并且是“黑色”的
·&&&&&&*&如果一个结点是“红色”的,那么它的两个子结点都是“黑色”的
·&&&&&&*&(注:也就是說,如果結點是黑色的,那么它的子節點可以是紅色或者是黑色的)。
·&&&&&&*&结点到其子孙结点的每条简单路径都包含相同数目的“黑色”结点
·&&&&&&*&根结点永远是“黑色”的
红黑树能够以O(log2&n)的时间复杂度进行搜索、插入、删除操作。此外,由于它的设计,任何不平衡都会在三次旋转之内解决。
·&&之所以称为红黑树的原因就在于它的每个结点都被“着色”为红色或黑色。这些结点颜色被用来检测树的平衡性。但需要注意的是,红黑树并不是平衡二叉树,恰恰相反,红黑树放松了平衡二叉树的某些要求,由于一定限度的“不平衡”,红黑树的性能得到了提升。
·&&从根结点到叶结点的黑色结点数被称为树的“黑色高度”(black-height)。前面关于红黑树的性质保证了从根结点到叶结点的路径长度不会超过任何其他路径的两倍。
对于给定的黑色高度为n的红黑树,从根到叶结点的简单路径的最短长度为n-1,最大长度为2(n-1)。
3&怎么样实现公平锁?实现机制?
同步队列啊有头信息获得锁之前看是否有前驱节点没有获得锁。
4&java引用类型有哪些?各有什么特点?
StrongReference
就可以他的名字一样,任何时候GC是不能回收他的,哪怕内存不足时,系统会直接抛出异常OutOfMemoryError,也不会去回收,首先要说明的是java中默认就是强引用,
SoftReference
软引用他的特点是当内存足够时不会回收这种引用类型的对象,只有当内存不够用时才会回收,这种特点很适合最一些缓存。
SoftReference&Person& personSoftReference = new&SoftReference&&(jack);
WeakReference
虚引用的特点是只要GC一运行就会把给回收了,个人感觉没多大用处,因为只要GC一运行他就会被回收了。
WeakReference&Person& personSoftReference = new&WeakReference&Person&(jack);
5&遇过哪些内存泄漏的问题?什么原因?
指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并非指内存在物理上的消失,而是分配某段内存后,由于设计错误,失去了对该段内存的控制,因而造成了内存的浪费。就算数据失效了,但是就是不可以gc.
内存泄露是指无用对象(不再使用的对象)持续占有内存或无用对象的内存得不到及时释放,从而造成的内存空间的浪费称为内存泄露。
1、静态集合类引起内存泄露:
像HashMap、Vector等的使用最容易出现内存泄露,这些静态变量的生命周期和应用程序一致,他们所引用的所有的对象Object也不能被释放,因为他们也将一直被Vector等引用着。
Static Vector v = new Vector(10);
for (int i = 1; i&100; i++)
Object o = new Object();
在这个例子中,循环申请Object对象,并将所申请的对象放入一个Vector中,如果仅仅释放引用本身(o=null),那么Vector仍然引用该对象,所以这个对象对GC来说是不可回收的。因此,如果对象加入到Vector后,还必须从Vector中删除,最简单的方法就是将Vector对象设置为null。
2、当集合里面的对象属性被修改后,再调用remove()方法时不起作用。
public static void main(String[] args)
Set&Person& set = new HashSet&Person&();
Person p1 = new Person("唐僧","pwd1",25);
Person p2 = new Person("孙悟空","pwd2",26);
Person p3 = new Person("猪八戒","pwd3",27);
set.add(p1);
set.add(p2);
set.add(p3);
System.out.println("总共有:"+set.size()+" 个元素!"); //结果:总共有:3 个元素!
p3.setAge(2); //修改p3的年龄,此时p3元素对应的hashcode值发生改变
set.remove(p3); //此时remove不掉,造成内存泄漏
set.add(p3); //重新添加,居然添加成功
System.out.println("总共有:"+set.size()+"个元素!"); //结果:总共有:4个元素!
for (Person person : set)
System.out.println(person);
在java编程中,我们都需要和监听器打交道,通常一个应用当中会用到很多监听器,我们会调用一个控件的诸如addXXXListener()等方法来增加监听器,但往往在释放对象的时候却没有记住去删除这些监听器,从而增加了内存泄漏的机会。
4、各种连接
比如连接(dataSourse.getConnection()),网络连接(socket)和io连接,除非其显式的调用了其close()方法将其连接关闭,否则是不会自动被GC回收的。对于Resultset和Statement对象可以不进行显式回收,但Connection一定要显式回收,因为Connection在任何时候都无法自动回收,而Connection一旦回收,Resultset和Statement对象就会立即为NULL。但是如果使用连接池,情况就不一样了,除了要显式地关闭连接,还必须显式地关闭Resultset Statement对象(关闭其中一个,另外一个也会关闭),否则就会造成大量的Statement对象无法释放,从而引起内存泄漏。这种情况下一般都会在try里面去的连接,在finally里面释放连接。
5、内部类和外部模块等的引用
内部类的引用是比较容易遗忘的一种,而且一旦没释放可能导致一系列的后继类对象没有释放。此外程序员还要小心外部模块不经意的引用,例如程序员A负责A模块,调用了B模块的一个方法如:
public void registerMsg(Object b);
这种调用就要非常小心了,传入了一个对象,很可能模块B就保持了对该对象的引用,这时候就需要注意模块B是否提供相应的操作去除引用。
6、单例模式
不正确使用单例模式是引起内存泄露的一个常见问题,单例对象在被初始化后将在JVM的整个生命周期中存在(以静态变量的方式),如果单例对象持有外部对象的引用,那么这个外部对象将不能被jvm正常回收,导致内存泄露,考虑下面的例子:
public A(){
B.getInstance().setA(this);
//B类采用单例模式
private static B instance=new B();
public B(){}
public static B getInstance(){
public void setA(A a){
//getter...
显然B采用singleton模式,它持有一个A对象的引用,而这个A类的对象将不能被回收。想象下如果A是个比较复杂的对象或者集合类型会发生什么情况
6&怎么样实现list的线程安全?
Copyandwritearraylist concurrent...Vector
7&怎么样实现一个缓存中的LRU算法?
8&listhashmap的原理
Java LinkedHashMap工作原理及实现
分享到:11
原文出处:
在理解了#7介绍的HashMap后,我们来学习LinkedHashMap的工作原理及实现。首先还是类似的,我们写一个简单的LinkedHashMap的程序:
LinkedHashMap&String, Integer& lmap = new LinkedHashMap&String, Integer&();
lmap.put("语文", 1);
lmap.put("数学", 2);
lmap.put("英语", 3);
lmap.put("历史", 4);
lmap.put("政治", 5);
lmap.put("地理", 6);
lmap.put("生物", 7);
lmap.put("化学", 8);
for(Entry&String, Integer& entry : lmap.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
运行结果是:
我们可以观察到,和HashMap的运行结果不同,LinkedHashMap的迭代输出的结果保持了插入顺序。是什么样的结构使得LinkedHashMap具有如此特性呢?我们还是一样的看看LinkedHashMap的内部结构,对它有一个感性的认识:
没错,正如官方文档所说:
Hash table and linked list implementation of the Map interface, with predictable iteration order. This implementation differs from HashMap in that it maintains a doubly-linked listrunning through all of its entries. This linked list defines the iteration ordering, which is normally the order in which keys were inserted into the map (insertion-order).
LinkedHashMap是Hash表和链表的实现,并且依靠着双向链表保证了迭代顺序是插入的顺序。
2. 三个重点实现的函数
在HashMap中提到了下面的定义:
// Callbacks to allow LinkedHashMap post-actions
void afterNodeAccess(Node&K,V& p) { }
void afterNodeInsertion(boolean evict) { }
void afterNodeRemoval(Node&K,V& p) { }
LinkedHashMap继承于HashMap,因此也重新实现了这3个函数,顾名思义这三个函数的作用分别是:节点访问后、节点插入后、节点移除后做一些事情。
afterNodeAccess函数
void afterNodeAccess(Node&K,V& e) { // move node to last
LinkedHashMap.Entry&K,V&
// 如果定义了accessOrder,那么就保证最近访问节点放到最后
if (accessOrder && (last = tail) != e) {
LinkedHashMap.Entry&K,V& p =
(LinkedHashMap.Entry&K,V&)e, b = p.before, a = p.
if (b == null)
if (a != null)
a.before =
if (last == null)
p.before =
last.after =
就是说在进行put之后就算是对节点的访问了,那么这个时候就会更新链表,把最近访问的放到最后,保证链表。
afterNodeInsertion函数
void afterNodeInsertion(boolean evict) { // possibly remove eldest
LinkedHashMap.Entry&K,V&
// 如果定义了移除规则,则执行相应的溢出
if (evict && (first = head) != null && removeEldestEntry(first)) {
K key = first.
removeNode(hash(key), key, null, false, true);
如果用户定义了removeEldestEntry的规则,那么便可以执行相应的移除操作。
afterNodeRemoval函数
void afterNodeRemoval(Node&K,V& e) { // unlink
// 从链表中移除节点
LinkedHashMap.Entry&K,V& p =
(LinkedHashMap.Entry&K,V&)e, b = p.before, a = p.
p.before = p.after =
if (b == null)
if (a == null)
a.before =
这个函数是在移除节点后调用的,就是将节点从双向链表中删除。
我们从上面3个函数看出来,基本上都是为了保证双向链表中的节点次序或者双向链表容量所做的一些额外的事情,目的就是保持双向链表中节点的顺序要从eldest到youngest。
9&手写一个算法,随便一个整数num,一个代表进制的整数k(小于10),实现num的k进制转换
10&实现一个算法,数据库有一个按顺序排列的歌单,用户在前台修改了顺序,现要把数据库的歌单修改成同样的顺序,问怎么样操作最少.
11&实现一个算法,一个文档有若干单词(内存放不下),现要求出10个频度最高的单词
12&jvm中适合高吞吐量的垃圾回收器
–同ParNew回收器一样, 不同的地方在于,它非常关注系统的吞吐量(通过参数控制)
–使用复制算法
–支持自适应的GC调节策略
(3)设置参数:
-XX:+UseParallelGC新生代用ParallelGC回收器, 老年代使用串行回收器
-XX:+UseParallelOldGC新生代用ParallelGC回收器, 老年代使用ParallelOldGC回收器系统吞吐量的控制:
-XX:MaxGCPauseMillis=n(单位ms) 设置垃圾回收的最大停顿时间,
-XX:GCTimeRatio=n(n在0-100之间)  设置吞吐量的大小, 假设值为n, 那系统将花费不超过1/(n+1)的时间用于垃圾回收
-XX:+UseAdaptiveSizePolicy打开自适应GC策略, 在这种模式下, 新生代的大小, eden,survivior的比例, 晋升老年代的对象年龄等参数会被自动调整,以达到堆大小, 吞吐量, 停顿时间之间的平衡点
13&cms垃圾回收器的特点
14&有几种垃圾回收算法
15&计算机网络osi模型
16&tcp如何实现拥塞控制和流量控制?具体算法是什么?
17&http头部格式
HTTP请求消息头部实例:
Host:rss.sina.com.cn
User-Agent:Mozilla/5、0 (W U; Windows NT 5、1; zh-CN; rv:1、8、1、14) Gecko/ Firefox/2、0、0、14
Accept:text/xml,application/xml,application/xhtml+xml,text/q=0、9,text/q=0、8,image/png,*/*;q=0、5
Accept-Language:zh-cn,q=0、5
Accept-Encoding:gzip,deflate
Accept-Charset:gb2312,utf-8;q=0、7,*;q=0、7
Keep-Alive:300
Connection:keep-alive
Cookie:userId=C5bYpXrimdmsiQmsBPnE1Vn8ZQmdWSm3WRlEB3vRwTnRtW &-- Cookie
If-Modified-Since:Sun, 01 Jun :30 GMT
Cache-Control:max-age=0
HTTP响应消息头部实例:
Status:OK - 200 &--响应状态码,表示web服务器处理的结果。
Date:Sun, 01 Jun :47 GMT
Server:Apache/2、0、61 (Unix)
Last-Modified:Sun, 01 Jun :30 GMT
Accept-Ranges:bytes
Content-Length:18616
Cache-Control:max-age=120
Expires:Sun, 01 Jun :47 GMT
Content-Type:application/xml
X-Cache:HIT from 236-41、D、sina、com、cn &--反向代理服务器使用的HTTP头部
Via:1.0 236-41.D.sina.com.cn:80 (squid/2.6.STABLE13)
Connection:close
18&实现一个用户登录功能,在不使用https的情况下完成安全传输
19&有哪些非对称加密算法
RSA, EI Gamal, ECC, Knapsack, etc.
RSA是企业级应用标准,很多第三方的加密软件使用RSA 2048bit加密。
ECC更高效,164bitECC约等于1024bit的RSA,经常使用在移动设备上。
20&linux了解吗?
21&class字节码文件格式是什么?
ClassFile中的字段简单说明如下:
1、MagicNumber:MagicNumber是用来标志class文件的,虚拟机加载class文件的时候会先检查这四个字节,如果不是cafe babe则虚拟机拒绝加载该文件,这样就可以防止加载非class文件而浪费系统资源。这个字段的长度是4个字节,值是固定的cafebabe。
2、Version:version字段有2个长度都为2字节的字段组成,分别是Major Version和Minor Version,分别代表当前class文件的主版本号和次版本号。随着Java技术的不断发展,Java class文件格式会增加一些新的内容来支持Java语言的新特性。同时,不同的虚拟机支持的Java class文件的版本范围是不同的,所以在加载class文件之前可以先看看该class文件是否在当前虚拟机的支持范围之内,避免加载不支持的class文件。
首先是2个字节的长度字段constant_pool_count,表明常量池包含了多少个常量。
后面跟着就是constant_pool_count个常量,常量池里放的是字面常量和符号引用。
字面常量主要包含文本串以及被声明为final的常量等;符号引用包含类和接口的全局限定名,字段的名称和描述符,方法的名称和描述符,因为java语言在编译的时候没有连接这一步,所有的引用都是运行时动态加载的,所以就需要把这些引用的信息保存在class文件里。
这里的常量又根据具体的类型分成字符串,整形,长整型,浮点型,双精度浮点型这几种基本类型。
而符号引用保存的是对应的引用的全局限定名,所以保存的是字符串。
4、access_flag 保存了当前类的访问权限
5、this_cass &保存了当前类的全局限定名在常量池里的索引
6、super class 保存了当前类的父类的全局限定名在常量池里的索引
7、interfaces 保存了当前类实现的接口列表,包含两部分内容:interfaces_count 和interfaces[interfaces_count]
interfaces_count 指的是当前类实现的接口数目
interfaces[] 是包含interfaces_count个接口的全局限定名的索引的数组
8、fields 保存了当前类的成员列表,包含两部分的内容:fields_count 和 fields[fields_count]
fields_count是类变量和实例变量的字段的数量总和。
fileds[]是包含字段详细信息的列表。
9、methods 保存了当前类的方法列表,包含两部分的内容:methods_count和methods[methods_count]
methods_count是该类或者接口显示定义的方法的数量。
method[]是包含方法信息的一个详细列表。
10、attributes 包含了当前类的attributes列表,包含两部分内容:attributes_count 和 attributes[attributes_count]
class文件的最后一部分是属性,它描述了该类或者接口所定义的一些属性信息。attributes_count指的是attributes列表中包含的attribute_info的数量。
属性可以出现在class文件的很多地方,而不只是出现在attributes列表里。如果是attributes表里的属性,那么它就是对整个class文件所对应的类或者接口的描述;如果出现在fileds的某一项里,那么它就是对该字段额外信息的描述;如果出现在methods的某一项里,那么它就是对该方法额外信息的描述。
22&模拟一个数据库死锁?如何解决死锁问题
23&mysql如何实现分页功能?
24&如果有一百万的数据,mysql如何实现高性能分页
25&数据库三个范式分别是什么?
26&堆排序时间复杂度,nlogn红黑树时间复杂度logn
27&jdk的bin目录下有哪些工具?怎么用?
28&类加载机制是什么,为什么实现双亲委派模型?
29&java的异常如何分类?
30&分布式的二阶段提交算法
可用于分布式任务
31&post和get有什么区别
32&ThreadLocal有什么问题&内存溢出&this.thread -& threadlocalmap -&(threadlocal实例,然后value)
33&不加锁实现阻塞队列
三次握手:
第一次握手:建立连接时,发送包(syn=j)到,并进入状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。
:收到包,必须确认客户的SYN(=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入状态;
第三次握手:收到器的SYN+ACK包,向发送确认包ACK(=k+1),此包发送完毕,客户端和服务器进入(TCP连接成功)状态,完成三次握手。
·&客户端先发送FIN,进入FIN_WAIT1状态
·&服务端收到FIN,发送ACK,进入CLOSE_WAIT状态,客户端收到这个ACK,进入FIN_WAIT2状态
·&服务端发送FIN,进入LAST_ACK状态
·&客户端收到FIN,发送ACK,进入TIME_WAIT状态,服务端收到ACK,进入CLOSE状态
·&客户端TIME_WAIT持续2倍MSL时长,在linux体系中大概是60s,转换成CLOSE状态
能不能发送完ACK之后不进入TIME_WAIT就直接进入CLOSE状态呢?不行的,这个是为了TCP协议的可靠性,由于网络原因,ACK可能会发送失败,那么这个时候,被动一方会主动重新发送一次FIN,这个时候如果主动方在TIME_WAIT状态,则还会再发送一次ACK,从而保证可靠性。那么从这个解释来说,2MSL的时长设定是可以理解的,MSL是报文最大生存时间,如果重新发送,一个FIN+一个ACK,再加上不定期的延迟时间,大致是在2MSL的范围。
回到上面的问题,go写了一个HTTP服务,压测发现TIME_WAIT过多。
首先判断是不是压测程序放在服务的同一台机器...当然不会犯这么低级的错误...
那么这个感觉就有点奇怪了,HTTP服务并没有依赖外部mysql或者redis等服务,就是一个简单的Hello world,而TIME_WAIT的是主动断开方才会出现的,所以主动断开方是服务端?
答案是是的。在HTTP1.1协议中,有个Connection头,Connection有两个值,close和keep-alive,这个头就相当于客户端告诉服务端,服务端你执行完成请求之后,是关闭连接还是保持连接,保持连接就意味着在保持连接期间,只能由客户端主动断开连接。还有一个keep-alive的头,设置的值就代表了服务端保持连接保持多久。
HTTP默认的Connection值为close,那么就意味着关闭请求的一方几乎都会是由服务端这边发起的。那么这个服务端产生TIME_WAIT过多的情况就很正常了。
虽然HTTP默认Connection值为close,但是现在的浏览器发送请求的时候一般都会设置Connection为keep-alive了。所以,也有人说,现在没有必要通过调整参数来使TIME_WAIT降低了。
短连接与长连接
通俗来讲,浏览器和服务器每进行一次通信,就建立一次连接,任务结束就中断连接,即短连接。相反地,假如通信结束(如完成了某个HTML文件的信息获取)后保持连接则为长连接。在HTTP/1.0中,默认使用短连接。从HTTP/1.1起,默认使用长连接,这样做的优点是显而易见的,一个网页的加载可能需要HTML文件和多个CSS或者JS,假如每获取一个静态文件都建立一次连接,那么就太浪费时间了,而在保持连接的情况下,继续GET即可。
对于频繁请求资源的客户来说,较适用长连接。但连接数最好进行限制,防止建立太多连接拖累服务端。一般浏览器对一个网站的连接是有限制的几个,所以网站会将资源部署在多个域名上以实现浏览器同时请求。
短/长连接应当在TCP连接的范畴中来讨论。有人常说HTTP的短连接和长连接如何如何,但是HTTP只是一个应用层协议,又是无状态的,最终实质性的保持连接还是得靠传输层,即TCP。
举个例子,NginX作为代理的一种常见配置方式是在NginX与客户端之间的连接使用长连接,NginX与后端服务器之间的连接使用短连接。
keep-alive
我们使用浏览器的开发者工具查看网络请求和响应信息时经常在HTTP请求头部看到Connection: keep-alive,一般的浏览器都会带着个头去请求数据,假如有特殊需求可以用Connection: close断开。HTTP头部的Connection也不一定就被客户端或服务端老老实实地遵循,毕竟各有各的考虑,尤其是在HTTP/1.0这还只是个实验性的功能,而在HTTP/1.1默认长连接于是没有对长连接做特殊的规定。
长连接也不能无限期地长,服务端有可能在头部放Keep-Alive,其中timeout等于一个值来规定保持连接的秒数,还可以用max来规定多少次请求后断开。如果没有说明怎么断开,主动发起四次握手也可以实现连接的断开。
现在有一个问题就是HTTP的keep-alive与TCP的keep-alive到底是什么关系。其实这是两种不同的机制,可以认为没有什么关系。HTTP在头部的Connection中声明keep-alive可以告诉对方要长连接不立即断开,但是TCP的keep-alive则是一种检查对方是否仍旧和自己保持着连接的机制以避免自作多情半开放的连接。假如发出一个探测段,成功收到响应,这证明连接正常保持;假如发出一个探测段一段时间后,一个响应都没收到,对方可能已挂断、机器异常或网络异常;假如对方收到探测段但重置,说明原来的连接已经因为某些原因挂断,目前是因为未进行三次握手新建立连接而被挂断。
算法性能测试?压力测试
互斥锁信号量
信号量与普通整型变量的区别:
①信号量(semaphore)是非负整型变量,除了初始化之外,它只能通过两个标准原子操作:wait(semap) , signal(semap) ;来进行访问;
②操作也被成为PV原语(P来源于Dutch proberen"测试",V来源于Dutch verhogen"增加"),而普通整型变量则可以在任何语句块中被访问;
信号量与互斥锁之间的区别:
1.&互斥量用于线程的互斥,信号线用于线程的同步。
这是互斥量和信号量的根本区别,也就是互斥和同步之间的区别。
互斥:是指某一资源同时只允许一个访问者对其进行访问,具有唯一性和排它性。但互斥无法限制访问者对资源的访问顺序,即访问是无序的。
同步:是指在互斥的基础上(大多数情况),通过其它机制实现访问者对资源的有序访问。在大多数情况下,同步已经实现了互斥,特别是所有写入资源的情况必定是互斥的。少数情况是指可以允许多个访问者同时访问资源
2.互斥量值只能为0/1,信号量值可以为非负整数。
也就是说,一个互斥量只能用于一个资源的互斥访问,它不能实现多个资源的多线程互斥问题。信号量可以实现多个同类资源的多线程互斥和同步。当信号量为单值信号量是,也可以完成一个资源的互斥访问。
3.互斥量的加锁和解锁必须由同一线程分别对应使用,信号量可以由一个线程释放,另一个线程得到。
项目的系统架构图》》》》
功能的流程图》》》
软件架构方面硬件架构方面
剥洋葱:客户端(技术)服务器(登录服务器业务逻辑服务器数据库服务器)每个服务器的业务需求。
服务器卡顿怎么排查:
free,top,iostat等等看看CPU,内存,网络情况
阻塞”与"非阻塞"与"同步"与“异步"不能简单的从字面理解,提供一个从分布式系统角度的回答。
1.同步与异步
同步和异步关注的是消息通信机制 (synchronous communication/ asynchronous communication)
所谓同步,就是在发出一个*调用*时,在没有得到结果之前,该*调用*就不返回。但是一旦调用返回,就得到返回值了。
换句话说,就是由*调用者*主动等待这个*调用*的结果。
而异步则是相反,*调用*在发出之后,这个调用就直接返回了,所以没有返回结果。换句话说,当一个异步过程调用发出后,调用者不会立刻得到结果。而是在*调用*发出后,*被调用者*通过状态、通知来通知调用者,或通过回调函数处理这个调用。
典型的异步编程模型比如Node.js
举个通俗的例子:
你打电话问书店老板有没有《分布式系统》这本书,如果是同步通信机制,书店老板会说,你稍等,”我查一下",然后开始查啊查,等查好了(可能是5秒,也可能是一天)告诉你结果(返回结果)。
而异步通信机制,书店老板直接告诉你我查一下啊,查好了打电话给你,然后直接挂电话了(不返回结果)。然后查好了,他会主动打电话给你。在这里老板通过“回电”这种方式来回调。
2.阻塞与非阻塞
阻塞和非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态.
阻塞调用是指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。
非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程。
还是上面的例子,
你打电话问书店老板有没有《分布式系统》这本书,你如果是阻塞式调用,你会一直把自己“挂起”,直到得到这本书有没有的结果,如果是非阻塞式调用,你不管老板有没有告诉你,你自己先一边去玩了, 当然你也要偶尔过几分钟check一下老板有没有返回结果。
在这里阻塞与非阻塞与是否同步异步无关。跟老板通过什么方式回答你结果无关。
如果是关心blocking IO/ asynchronous IO, 参考 Unix Network Programming
linux进程间通讯的几种方式的特点和优缺点,和适用场合
由于不同的进程运行在各自不同的内存空间中.一方对于变量的修改另一方是无法感知的.因此.进程之间的信息传递不可能通过变量或其它数据结构直接进行,只能通过进程间通信来完成。
管道&(&pipe&):
管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。&&&有名管道&(named&pipe)&:
有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。
信号量(&semophore&):
信号量是一个计数器,可以用来控制多个进程对共享资源的访问。
它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作
为进程间以及同一进程内不同线程之间的同步手段。&&#&消息队列(&message&queue&)&:&消息队列是由消息的链表,存放在内核中并由消息队列标识
符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
信号&(&sinal&)&:
信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。
#共享内存(&shared&memory):共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的IPC
方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,
如信号量,配合使用,来实现进
程间的同步和通信。
#&套接字(&socket&)&:
套解口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同及其间的进程通信。
管道的主要局限性正体现在它的特点上:
只支持单向数据流;
只能用于具有亲缘关系的进程之间;&没有名字;
管道的缓冲区是有限的(管道制存在于内存中,在管道创建时,为缓冲区分配一个页面大小);
管道所传送的是无格式字节流,这就要求管道的读出方和写入方必须事先约定好数据的格式,比如多少字节算作一个消息(或命令、或记录)等等;
管道通信(PIPE)
两个进程利用管道进行通信时.发送信息的进程称为写进程.接收信息的进程称为读进程。管道通信方式的中间介质就是文件.通常称这种文件为管道文件.它就像管道一样将一个写进程和一个读进程连接在一起,实现两个进程之间的通信。写进程通过写入端(发送端)往管道文件中写入信息;读进程通过读出端(接收端)从管道文件中读取信息。两个进程协调不断地进行写和读,便会构成双方通过管道传递信息的流水线。
利用系统调用PIPE()可以创建一个无名管道文件,

我要回帖

更多关于 剑三重置版微端 的文章

 

随机推荐