面试:面经笔记 2017.7

按牛客网讨论区笔经面经的发表时间排序。html

 


 

阿里内推,蚂蚁金服---java开发工程师第一次电话面试

1.TCP三次握手java

(记住1.过程;2.状态变化;3.几个常见问题)linux

第一次:客户端给服务器发送syn包x;SYN_SENTc++

第二次:服务器接收到syn包,返回一个syn包y 和 一个ack包x+1; SYN_RECV面试

第三次:客户端收到syn+ack包,向服务器发送ack包。ESTABLISHEDredis

为何三次握手?算法

防止已失效的链接请求报文段重传。spring

四次挥手?数据库

把三次握手的第二次分解,先发ack包,再发fin包。express

第一次:主动关闭方发送fin包x,关闭数据传送; FIN_WAIT1  CLOSE_WAIT

第二次:被动方发送ack包x+1; FIN_WAIT2

第三次:被动方发送fin包y,关闭数据传送; TIME_WAIT  LASH_ACK

第四次:主动方发送ack包y+1;

为何四次握手?

被动方收到FIN包时,并不会当即关闭socket,因此先回复一个ack包。等到被动方全部数据发送完,再发fin包。

为何TIME_WAIT/等待2MSL?

MSL是报文最大生存时间;主动方发出最后一个ACK包进入TIME_WAIT状态,目的是防止最后一个ACK包对方没接收到,那么对方在超时后将重发第三次握手的FIN包。 A->ACK->B,等待ACK到达对方时间MSL,等待FIN超时重传MSL,因此若是2MSL时间没有收到FIN,说明对方安全收到FIN。

 

2.在浏览器访问一个网址的过程?

  1.首先浏览器经过DNS解析网址的IP地址,经过IP找到服务器路径;

  2.根据IP地址向服务器发送一个HTTP请求;

  3.服务器收到请求,返回响应;

  4.浏览器对网页解析,渲染显示。

涉及各层协议?

应用层:HTTP、DNS、(DNS解析域名为目的IP,经过IP找到服务器路径,客户端向服务器发起HTTP会话)

传输层:TCP、 (HTTP会话会被分红报文段,添加源、目的端口;TCP协议进行主要工做)

网际层:IP、(ARP)、ICMP、(为数据包选择路由,IP协议进行主要工做)

链路层:PPP、(ARP)(发送IP数据包到达服务器的地址,ARP协议将IP地址转成MAC地址)

 

3.Linux文件的权限;

4.排序算法有哪些?时间复杂度是?

(还须要记住最好最坏时间复杂度、稳定性)

O(n^2):

选择排序:O(n^2)、O(n^2); 不稳定

冒泡排序:O(n)、O(n^2); 稳定

插入排序:O(n)、O(n^2); 稳定

O(nlogn):

快速排序:O(nlogn)、O(n^2);空间:O(logn) 不稳定

归并排序:O(nlogn)、O(nlogn);空间:O(n)  稳定

堆排序:O(nlogn)、O(nlogn);空间:O(1) 稳定

 

5.在线编程?

 


 

阿里一面17分钟

1.==和equals的区别?

(1.基本类型; 2.基本类型封装;3.String;4.非字符串变量)

equals()是Object类的方法;

(1) 若是是基本类型比较,那么只能用==来比较,用equals会编译错误,由于不是对象。int a = 3;

(2) 对于基本类型的包装类型,好比Boolean、Character、Byte、Shot、Integer、Long、Float、Double等的引用变量,==是比较地址的,而equals是比较内容的。Integer n1 = new Integer(30);

(2.5)对于String a = “a”; Integer b = 1;这种类型的特有对象建立方式,==的时候值是相同的。

(3)对于字符串变量来讲,使用“==”和“equals()”方法比较字符串时,其比较方法不一样。

“==”比较两个变量自己的值,即两个对象在内存中的首地址。

“equals()”比较字符串中所包含的内容是否相同。

String s1 = "123"; 
String s2 = "123"; 

String s4 = new String("123"); 
String s5 = new String("123"); 

s1==s2 true;   s1.equals(s2) true;   

s4==s5 false;   s4.equals(s5) true;

s1==s4 false;   s1.equals(s4) true;

s1/s2分别指向字符串常量"123"建立的对象,在常量池里只有一个对象,内容为"123";

s4/s5两个引用对象指向的对象内容相同,可是new操做符建立的,内存中分配两块空间给这两个对象,因此内存地址不一样。

(4)对于非字符串变量来讲,"=="和"equals"方法的做用是相同的都是用来比较其对象在堆内存的首地址,即用来比较两个引用变量是否指向同一个对象。

 

2.string是否是基本数据类型,

不是,String是类类型,基本类型有八种:

整型4种:byte/short/int/long  字节数:1/2/4/8

字符型1种:char  2

浮点型2种:float/double  4/8

布尔型1种:boolean 1/8

一个字节等于8位,等于256个数,就是-128到127

大写的B表示Bytes=字节;小写的b表示bit=位;1byte=8bit;

自动转换:(小可转大,大转小会失去精度)

byte -> short/char -> int -> long -> float -> double

 

3.char能不能存放汉字?

能,一个char字符能够存储一个中文汉字。

 

4.error/exception/runtime exception区别?

Error和Exception都实现了Throwable接口 
Error指的是JVM层面的错误,好比内存不足OutOfMemoryError
Exception 指的是代码逻辑的异常,好比下标越界OutOfIndexException

Exception分为可查异常CheckedException和运行时异常RuntimeException:

可查异常是必须处理的异常,要么try catch住,要么往外抛,谁调用,谁处理,好比 FileNotFoundException、IOException、SQLException等。若是不处理,编译器就不让你经过。

运行时异常 又叫作非可查异常,在编译过程当中,不要求必须进行显示捕捉。

常见的Runtime Excepiton?

NullPointerException 空指针异常
ArithmeticException 算术异常,好比除数为零
ClassCastException 类型转换异常
ConcurrentModificationException 同步修改异常,遍历一个集合的时候,删除集合的元素,就会抛出该异常 
IndexOutOfBoundsException 数组下标越界异常
NegativeArraySizeException 为数组分配的空间是负数异常

为何分两种异常?

Java之因此会设计运行时异常的缘由之一,是由于下标越界,空指针这些运行时异常太过于广泛,若是都须要进行捕捉,代码的可读性就会变得很糟糕。

 

5.object类的方法?

9种;(简要介绍各方法)

  1.对象的复制/获取/String/释放:clone/getClass/toString/finalize;

  2.hash:equals/hashCode;

  3.多线程:wait/notify/notifyAll

clone:实现对象的浅复制;

getClass:得到运行时类对象;

finalize:用于释放资源;

equals:比较对象是否相等;基本类型不能够用equals,对于String类型“equals”和“==”做用不一样;

hashcode:用于hash寻找;

wait:使当前线程等待该对象的锁,当前线程必须是该对象的拥有者,也就是具备该对象的锁;wait()方法一直等待,直到得到锁或者被中断。wait(longtimeout)设定一个超时间隔,若是在规定时间内没有得到锁就返回。

调用该方法后当前线程进入睡眠状态,直到如下事件发生:

(1)其余线程调用了该对象的notify方法。

(2)其余线程调用了该对象的notifyAll方法。

(3)其余线程调用了interrupt中断该线程。

(4)时间间隔到了。

此时该线程就能够被调度了,若是是被中断的话就抛出一个InterruptedException异常。

notify:唤醒在该对象上等待的某个线程

6.jvm垃圾回收

7.linux查看日志文件的方式?

 


 

蚂蚁金服Java面经

1.Java都学了些什么?
答:集合、IO、多线程、框架等等

2.说说多线程
答:说了一下多线程的实现,同步,优化

(tips:对于大范围的内容要整理出目录,否则会很乱。)

进程和线程的区别 感受有点偏题就不写了

多线程的实现?

三种方法:1.继承Thread类;2.实现Runnable接口;3.使用Executor建立线程池;

多线程的同步?

(1)同步方法:synchronized修饰的方法;

(2)同步代码块:同步是一种高开销的操做,所以应该尽可能减小同步的内容。一般没有必要同步整个方法,使用synchronized代码块同步关键代码便可。

  同步方法和同步代码块的区别是什么?

  答:同步方法默认用this或者当前类class对象做为锁; 同步代码块能够选择以什么来加锁,比同步方法要更细颗粒度,咱们能够选择只同步会发生同步问题的部分代码而不是整个方法。

(3)使用volatile实现同步:每次线程要访问volatile修饰的变量时都是从内存中读取,而不是从缓存当中读取,所以每一个线程访问到的变量值都是同样的。这样就保证了同步。

(4)使用重入锁实现线程同步:ReentrantLock是concurrent包的类;经常使用方法有lock()和unlock();能够建立公平锁;支持非阻塞的tryLock(可超时);须要手动释放锁。

(5)使用ThreadLocal实现线程同步:每一个线程都建立一个变量副本,修改副本不会影响其余线程的副本。ThreadLocal并不能替代同步机制,二者面向的问题领域不一样。同步机制是为了同步多个线程对相同资源的并发访问,是为了多个线程之间进行通讯的有效方式;而ThreadLocal是隔离多个线程的数据共享,从根本上就不在多个线程之间共享资源(变量)。

多线程的优化?

影响多线程性能的问题:死锁、过多串行化、过多锁竞争等;

预防和处理死锁的方法:

  1)尽可能不要在释放锁以前竞争其余锁;通常能够经过细化同步方法来实现;

  2)顺序索取锁资源;

  3)尝试定时锁tryLock();

下降锁竞争方法:

  1)缩小锁的范围,减少锁的粒度;

  2)使用读写分离锁ReadWriteLock来替换独占锁:来实现读-读并发,读-写串行,写-写串行的特性。这种方式更进一步提升了可并发性,由于有些场景大部分是读操做,所以不必串行工做。


3.说一下线程池,线程池里面的线程的状态有哪些?

线程池:

(1.建立;2.参数;)

线程池的顶级接口是Executor,是执行线程的工具;真正的线程池接口是ExecutorService。ThreadPoolExecutor是ExecutorService的默认实现。

ThreadPoolExecutor的参数有:

corePoolSize - 池中所保存的线程数,包括空闲线程。

maximumPoolSize-池中容许的最大线程数。

keepAliveTime - 当线程数大于核心时,此为终止前多余的空闲线程等待新任务的最长时间。

unit - keepAliveTime 参数的时间单位。

workQueue - 执行前用于保持任务的队列。此队列仅保持由 execute方法提交的 Runnable任务。

threadFactory - 执行程序建立新线程时使用的工厂。

handler - 因为超出线程范围和队列容量而使执行被阻塞时所使用的处理程序。

线程的状态:(把那张图将熟悉)

包括New、Runnable、Running、Blocked、Dead状态;

1)New:Thread t = new Thread();

2)Runnable:t.start()后进入Runnable状态;位于可运行线程池中,等待被线程调度选中,得到CPU使用权;

3)Running:Runnable状态的线程得到了cpu时间片;

4)Blocked:三种状况;

  1.等待阻塞:o.wait(),释放锁;进入等待队列;o.notify()/notifyAll() 进入锁池;

  2.同步阻塞:同步锁被别的线程占用;进入锁池;

  3.其余阻塞:1)Thread.sleep();2)t2.join();3)等待用户输入(发出I/O请求);不会释放锁;当sleep时间结束,t2线程结束,I/O处理完成后进入Runnable状态;

5)Dead:run()/main()执行结束 或者 异常退出;线程结束生命周期。

 

4.数据结构学了些什么?

数组、HashMap、栈、队列、链表、树;(HashMap也算?)

(把方向引向本身擅长的部分)

 

5.Hashmap和Hashtable的区别?

相同点:都实现了Map接口;

不一样点-两个方面:null值,同步;

HashMap容许键和值是null,HashTable不容许;

HashTable是同步的,HashMap不是;

 

6.Hashmap的数据结构,Hash的具体实现(这块答得很差)

(讲HashMap:1.结构+原理;2.其余参数-容量、负荷系数、阈值;)

  1)HashMap是有数组+链表组成,Entry数组是HashMap的主体,链表是为了解决Hash冲突;

  2)HashMap的Entry数组的元素能够看做是一个个散列桶,每一个桶是一个单链表;每一个Entry内部类有四个字段:key/value/hash/next;

  3)执行put时,根据key的hashcode定位到桶;遍历单链表,利用key.equals()检查key是否存在;若是存在则覆盖;不然新建Entry放在头部;

  4)执行get时,根据key的hashcode定位到桶;遍历单链表,利用key.equals()获取对应的Entry,返回它的value;

  5)参数:容量capacity(默认16)、负载系数loadFactor(默认0.75)、阈值threshold=容量*负载系数。数组容量capacity必须是2的n次方,当键值对个数>threshold(12)时,扩容:将数组扩容为原来容量的二倍。

几点补充:

  1)根据hashcode定位桶步骤:

int hash = hash(key.hashCode());     //计算key.hashcode()的hash值,hash函数由hashmap本身实现
int i = indexFor(hash, table.length);//获取将要存放的数组下标

 也就是首先计算key的hashcode(),再对该值map的自定义hash()(将hash值打散,使插入的Entry落在不一样的桶上,提升查询效率),再根据获得的hash值调用indexFor()方法;indexFor(h,length)方法:将hash值与entry数组的长度-1按位与;

    /**
     * "按位与"来获取数组下标
     */
    static int indexFor(int h, int length) {
        return h & (length - 1);
    }

  2)为何保持Entry数组大小2的n次方?

当length老是2的n次方时,h& (length-1)运算等价于对length取余,也就是h%length,可是&比%具备更高的效率。

参考:HashMap源码

 

7.设计模式有了解吗?
答:谈了一下单例模式、工厂模式、代理模式,顺便说了一下Spring的AOP是基于代理模式的,能够实现日志记录等功能。

代理模式

 

8.数据库事务你了解吗?脏读是什么,幻读是什么?

(说一下事务的四个特性+四个冲突+四个隔离级别) 

 


 

阿里内推一面,已跪

[阿里] [c++]

1.讲一下Linux下如何将源文件逐步编译成目标文件的过程 

2.你简历上写熟悉TCP/IP协议,那你说一下TCP的报头吧。

/*TCP头定义,共20个字节*/
typedef struct _TCP_HEADER 
{
 short m_sSourPort;              // 源端口号16bit
 short m_sDestPort;              // 目的端口号16bit


 unsigned int m_uiSequNum;         // 序列号32bit
 unsigned int m_uiAcknowledgeNum;  // 确认号32bit


 short m_sHeaderLenAndFlag;        // 前4位:TCP头长度;中6位:保留;后6位:标志位
 short m_sWindowSize;            // 窗口大小16bit


 short m_sCheckSum;              // 检验和16bit
 short m_surgentPointer;           // 紧急数据偏移量16bit
}__attribute__((packed))TCP_HEADER, *PTCP_HEADER;

参考:IP头、TCP头、UDP头

 

3. 你简历上写的掌握经常使用的数据结构和排序算法,那你说一个你熟悉的排序算法吧,冒泡就不用说了 。(注:原理+复杂度+手写代码)

排序主要用这六种:

O(n^2)的有:冒泡排序、插入排序、选择排序;

O(nlogn)的有:快排、归并排序、堆排序;

冒泡排序:原理是无序区两两比较,每趟获得一个最大的放在无序区最后;

  算法:外循环是趟数[0,n-1), 内循环是无序区个数[0, n-i-1);循环体是比较[j]和[j+1];

插入排序:是把数组分红有序区和无序区两部分,每次从无序区取出一位做为tar值,从后向前遍历有序区,大于tar则后移,最后放到目标位置;

  算法:外循环是无序区长度[1,n);定义a[i]为tar值;内循环j指向i,比较a[j-1]与tar,大于则日后顺移a[j-1];最后a[j]赋值;

选择排序:也是分为有序区和无序区,每次从无序区选择一位最小的放到有序区末尾;

  算法:外循环是趟数[0,n-1), 内循环是无序区个数[i+1,n);循环体是比较[i]和[j];

快排:每次排序肯定一个数的位置,比该数小的移到左边,大的移到右边。一趟快排的算法是:

  • 设置两个首尾指针lo、hi;
  • 以第一个元素做为key值;
  • 从hi向前搜索,若是大于key则hi--,小于key则[lo]=[hi]把[hi]移到前面;
  • 从lo向后搜搜,若是小于key则lo++,大于key则[hi]=[lo]把[lo]移到后面;
  • 重复三、4步骤,直到lo=hi;返回lo位置。

上述过程就是partition函数;以partition函数返回的位置,对左右两边递归。

  算法:(如上)partition(a,lo,hi)函数:定义key,while循环(lo<hi),内部(lo<hi && a[hi]>=key);最后a[lo]赋值,返回lo; sort(a,lo,hi)函数:判断(lo<hi),index,递归;

归并排序:将数组分红若干个小数组,将已有序的数组两两归并获得彻底有序数组。每趟归并的算法是:

  • 申请空间tmp[],大小是两个已排数组的和,[hi-lo+1];
  • 设定两个指针,分别指向两个已排数组的起始位置;
  • 比较两个指针元素的值,选择小的元素放到tmp[]里,并移动指针;
  • 重复步骤3,直到某一指针到数组尾;
  • 将另外一序列剩下的全部元素复制到tmp[]里;
  • 将tmp[]数组覆盖原num[]数组;

  算法:merge(a,lo,mid,hi)方法:tmp[]数组,左右指针+临时指针,比较两数组小的保存,保存剩余数组,赋值数组;mergeSort(a,lo,hi) mid, if()判断:左右递归,merge();注意左右递归必定是左边(lo,mid),右边(mid+1, hi);由于mid偏左,否则会死循环。

堆排序:堆排序包括两个过程,首先是根据元素建堆,时间复杂度O(n),而后将堆的根节点取出(与最后一个节点交换),将前面N-1个节点进行堆调整。直至全部节点都取出。堆调整时间复杂是O(lgn),调用了n-1次,因此堆排序时间复杂度是O(nlgn);

  • 建堆:建堆是不断调整堆的过程;从len/2出开始调整(最后一个父节点)。最后一层父节点最多下调1次,倒数第二层最多下调2次,顶点最多下调H=logN次。而最后一层父节点共有2^(H-1)个,倒数第二层公有2^(H-2),顶点只有1(2^0)个,因此总共的时间复杂度为s = 1 * 2^(H-1) + 2 * 2^(H-2) + ... + (H-1) * 2^1 + H * 2^0。将H代入后s= 2N - 2 - log2(N),近似的时间复杂度就是O(N)。
  • 调整堆:思想是比较节点i和它的孩子节点left(i),right(i),若i不是最大则调换。

 


  

蚂蚁金服java工程师面经 

 
1 自我介绍
2 介绍项目,在项目中图片存储在公有云上加密问题,项目中为何用redis以及怎么实现相关功能的
 
 
3 说说你学java都学了哪些内容
基础的:面向对象、操做符、控制流程(条件判断、循环语句)、数组、类和对象、接口与继承等;
中级的:异常处理、集合框架、多线程等;
J2EE的:Servlet、JSP等;
框架:Spring、Spring MVC、MyBatis、Spring Boot、Spring Data JPA;
 
 
 
4 项目中用过的开源框架,为何要用springboot 和 hibernate
 
 
5 spring的核心功能是什么,介绍一下 AOP以及怎么实现的,jdk代理和cglib代理的区别
 
核心功能是IoC反转控制和AOP面向切面编程;
AOP(Aspect-OrientedProgramming,面向方面编程), 能够说是OOP(Object-Oriented Programing,面向对象编程)的 补充和完善。OOP引入封装、继承和多态性等概念来创建一种对象层次结构,用以模拟公共行为的一个集合 。当咱们须要为分散的对象引入公共行为的时候,OOP则显得无能为力。也就是说,OOP容许你定义从上到下的关系,但并不适合定义从左到右的关系。例如日志功能。日志代码每每水平地散布在全部对象层次中,而与它所散布到的对象的核心功能毫无关系。对于其余类型的代码,如安全性、异常处理和透明的持续性也是如此。这种散布在各处的无关的代码被称为横切(cross-cutting)代码,在OOP设计中,它致使了大量代码的重复,而不利于各个模块的重用。
而AOP技术则偏偏相反,它利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其名为“Aspect”,即方面。所谓“方面”,简单地说,就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减小系统的重复代码,下降模块间的耦合度,并有利于将来的可操做性和可维护性。
实现AOP的技术,主要分为两大类:一是采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;二是采用静态织入的方式,引入特定的语法建立“方面”,从而使得编译器能够在编译期间织入有关“方面”的代码。
JDK动态代理和CGLIB字节码生成的区别?
 * JDK动态代理只能对实现了接口的类生成代理,而不能针对类
 * CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法。
参考: AOP原理(好,读!)、 JDK与CGLib
 
 
6 数据库的四大特性, 事务的隔离级别,幻读。
 
四大特性是:ACID 原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)+介绍四个特性概念;
事务隔离级别:读未提交(Read uncommitted)、读已提交(Read committed)、可重复读(Repeatable read)和串行化(Serializable)+介绍;
四大冲突问题:脏读、不可重复读、幻读、更新丢失;
 
 
7 计算机网络都学了什么(相似说书上的目录), OSI七层每层的任务,数据链路层的功能(答得不全)和协议。
 
包括:OSI参考模型以及各层的学习、TCP/IP协议、HTTP这些;
OSI七层自底向上是:物理层、数据链路层、网络层、传输层、会话层、表示层、应用层;
各层功能和协议:
物理层:经过媒介传输比特,肯定机械及电气规范(比特Bit)
数据链路层:将比特组装成帧和点到点的传递( 帧Frame) PPP点对点协议、ARP地址解析协议;
网络层:负责数据包从源到宿的传递和网际互连( 包Packet) IP、ICMP、RARP、RIP
传输层:提供端到端的可靠报文传递和错误恢复( 段Segment) TCP、UDP
会话层:创建、管理和终止会话(会话协议数据单元SPDU)
表示层:对数据进行翻译、加密和压缩(表示协议数据单元PPDU)
应用层:容许访问OSI环境的手段(应用协议数据单元APDU)FTP、DNS、HTTP
(注:ARP在OSI里是链路层,在TCP/IP里是网络层)
 
 
8 数据结构都学了什么, 排序算法最快的是哪一种说说原理,哪些是不用申请额外空间的
数组、链表、队列、栈、树;
 
9 树的非递归遍历以及三种遍历知道哪两种不能肯定一棵树
中序前序后序,非递归使用Stack栈来实现;
中序:向左一直遍历而且放入stack里,直到最左边,pop、add和遍历右边;
前序:先放入root,pop,而后依次放入右边和左边的;
后序:前序的次序变换一下,而且用llist.add(0,val);
 
10 介绍一下 二叉平衡树
二叉平衡树就是两个子树的深度差不超过1;
判断二叉平衡树的算法实现:
自顶向下:depth求深度,要求两个字数深刻差不超过1而且两个字数均为平衡树;
自底向上:不平衡的子树用-1标注;
 
11 是否看过jdk 源码,说说你说看过的
集合框架的HashMap、Concurrent下的ConHashMap、Executor等;
(todo)
 
12 说说 concurrent包下的类,而后问了一下Reentrantlock.
Concurrent包下的类包括:
并发集合类:ConcurrentHashMap、CopyOnWriteArrayList、CopyOnWriteArraySet、ArrayBlockingQueue、LinkedBlockingQueue;
原子类:AtomicInteger
线程池:ThreadPoolExecutor、Executor;
锁:ReentrantLock、ReentrantReadWriteLock;
(重点准备!)
 
13 之后的职业规划
 

 

人生第一次技术面试 蚂蚁金服 

 

1.ArrayList和LinkedList的区别

三个方面:1.实现;2.查询、增删;3.内存;

 

2.知道乐观锁,悲观锁么?什么状况下用乐观什么状况下用悲观么?

乐观锁:默认读数据的时候不会修改,因此不会上锁;

悲观锁:默认读数据的时候会修改,因此会上锁;

乐观锁适用于多读写比较少的状况,省去锁的开销,加大系统的吞吐量。

 

3.volatile关键字的做用?i++是原子性的么?

  在当前的Java内存模型下,线程能够把变量保存在本地内存(好比机器的寄存器)中,而不是直接在主存中进行读写。这就可能形成一个线程在主存中修改了一个变量的值,而另一个线程还继续使用它在寄存器中的变量值的拷贝,形成数据的不一致。 

  要解决这个问题,只须要像在本程序中的这样,把该变量声明为volatile(不稳定的)便可,这就指示JVM,这个变量是不稳定的,每次使用它都到主存中进行读取。通常说来,多任务环境下各任务间共享的标志都应该加volatile修饰。 

  Volatile修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。并且,当成员变量发生变化时,强迫线程将变化值回写到共享内存。这样在任什么时候刻,两个不一样的线程老是看到某个成员变量的同一个值。 

  使用volatile关键字修饰变量,线程要访问变量时都是从内存中读取,而不是从缓存当中读取,所以每一个线程访问到的变量值都是同样的。

  i++不是原子操做,分为三个阶段:内存到寄存器、寄存器自增、写会内存;这三个阶段中间均可以被中断分离开.

 

4.Java内存模型?为何设置工做内存和主内存?

PS:JVM内存模型和JMM(Java内存模型)没有关系。JMM的目的是为了解决Java多线程对共享数据的读写一致性问题。

 
全部线程共享主内存
每一个线程有本身的工做内存
refreshing local memory to/from main memory must  comply to JMM rules
 
每一个线程都有本身的执行空间(即工做内存),线程执行的时候用到某变量,首先要将变量从主内存拷贝的本身的工做内存空间,而后对变量进行操做:读取,修改,赋值等,这些均在工做内存完成,操做完成后再将变量写回主内存;
 
工做内存可类比高速缓存,为了得到更好的执行性能。
 
参考: 线程内存模型
 
5. GC的过程。
对象根据被存活的时间被分为:年轻代、年老代、永久代;
年轻代:对象被建立时,内存分配首先发生在年轻代,年轻代分为三个区域:Eden区、S0、S1;
建立时分配在Eden去,满的时候执行Minor GC,消亡的对象清理,剩余的复制到S0;Eden再满时,Minor GC,存活的复制到S1,将S0消亡的清除,能够晋级的到Old,存的的到S1。切换屡次,仍然存活的复制到老年代。
年老代:内存不足时执行Full GC,标记整理。
 
6. GC时会对程序有什么影响?当发现虚拟机频繁GC时应该怎么办?
"stop-the-world" 机制简称STW,即,在执行垃圾收集算法时,Java应用程序的其余全部除了垃圾收集器线程以外的线程都被挂起。
频繁GC:须要调优,好比控制新生代老年代比例,控制进入老年代前生存次数,控制年轻代eden和survivor比例(默认8:1)等;
 
7.Java8有什么新特性,知道 lambda表达式么?

1.Lambda表达式的形式化表示以下所示

Parameters -> an expression 

2.若是Lambda表达式中要执行多个语句块,须要将多个语句块以{}进行包装,若是有返回值,须要显示指定return语句,以下所示:

Parameters -> {expressions;};

3.若是Lambda表达式不须要参数,可使用一个空括号表示,以下示例所示

() -> {for (int i = 0; i < 1000; i++) doSomething();};

5.若是Lambda表达式只有一个参数,而且参数的类型是能够由编译器推断出来的,则能够以下所示使用Lambda表达式,便可以省略参数的类型及括号

Stream.of(datas).forEach(param -> {System.out.println(param.length());});

参考:lambda表达式 

 

9.设计模式知道么?

单例模式、工厂模式、观察者模式;

单例模式:

1.特色:

  • 只能有一个实例;
  • 必须本身建立本身的惟一实例;
  • 必须给其余对象提供这一实例;

2.单例模式有两种写法:饿汉式和懒汉式;饿汉式是一旦类加载了,就把单例初始化完成;而懒汉式只有在调用getInstance的时候,才初始化这个单例。

3.懒汉式单例:

a.写代码(构造方法,建立实例,get);

b.非线程安全;

c.三种线程安全的代码+优缺点

  syn:每次获取都须要同步,影响性能;

  双重检查:判空后锁住类;为何要第二次检查?建立实例的操做非原子化;在getInstance中作了两次null检查,确保了只有第一次调用单例的时候才会作同步,这样也是线程安全的,同时避免了每次都同步的性能损耗;

  静态内部类:LazyHolder;利用了classloader的机制来保证初始化instance时只有一个线程,因此也是线程安全的,同时没有性能损耗;

4.饿汉式单例:线程安全;在类建立的同事就实例化一个静态对象出来。

工厂模式:

见印象笔记/设计模式;工厂方法模式和抽象工厂模式区别;

观察者模式:

角色:抽象观察者-update、具体观察者、抽象被观察者-attach/detach/notify、具体被观察者;

使用场景:一个对象状态更新,其余对象同步更新,只须要将本身更新通知给其余对象而不须要知道其余对象细节。解耦,各自变换互不影响。

 

10.项目难点?

相关文章
相关标签/搜索