面试题总结

1、Java 中能创建 Volatile 数组吗?

能,Java 中可以创建 volatile 类型数组,不过只是一个指向数组的引用,而不是整个数组。我的意思是,如果改变引用指向的数组,将会受到 volatile 的保护,但是如果多个线程同时改变数组的元素,volatile 标示符就不能起到之前的保护作用了。

2、volatile 能使得一个非原子操作变成原子操作吗?

一个典型的例子是在类中有一个long 类型的成员变量。如果你知道该成员变量会被多个线程访问,如计数器、价格等,你最好是将其设置为 volatile。为什么?因为 Java 中读取long 类型变量不是原子的,需要分成两步,如果一个线程正在修改该 long 变量的值,另一个线程可能只能看到该值的一半(前 32 位)。但是对一个 volatile 型的 long 或double 变量的读写是原子。

3、volatile 修饰符的有过什么实践?

一种实践是用 volatile 修饰 long 和 double 变量,使其能按原子类型来读写。

double 和 long 都是64位宽,因此对这两种类型的读是分为两部分的,第一次读取第一个 32 位,然后再读剩下的 32 位,这个过程不是原子的,但Java 中 volatile 型的 long 或 double 变量的读写是原子的。volatile 修复符的另一个作用是提供内存屏障(memory barrier),例如在分布式框架中的应用。简单的说,就是当你写一个 volatile 变量之前,Java 内存模型会插入一个写屏障(writebarrier),读一个volatile 变量之前,会插入一个读屏障(read barrier)。意思就是说,在你写一个volatile 域时,能保证任何线程都能看到你写的值,同时,在写之前,也能保证任何数值的更新对所有线程是可见的,因为内存屏障会将其他所有写的值更新到缓存。

4、volatile 类型变量提供什么保证?

volatile 变量提供顺序和可见性保证,例如,JVM或者 JIT为了获得更好的性能会对语句重排序,但是 volatile 类型变量即使在没有同步块的情况下赋值也不会与其他语句重排序。 volatile 提供 happens-before 的保证,确保一个线程的修改能对其他线程是可见的。某些情况下,volatile 还能提供原子性,如读 64 位数据类型,像 long 和 double 都不是原子的,但 volatile 类型的 double 和 long 就是原子的。

5、10 个线程和 2 个线程的同步代码,哪个更容易写?

从写代码的角度来说,两者的复杂度是相同的,因为同步代码与线程数量是相互独立的。但是同步策略的选择依赖于线程的数量,因为越多的线程意味着更大的竞争,所以你需要利用同步技术,如锁分离,这要求更复杂的代码和专业知识。

6、你是如何调用 wait()方法的?使用 if 块还是循环?为什么?

wait() 方法应该在循环调用,因为当线程获取到CPU 开始执行的时候,其他条件可能还没有满足,所以在处理前,循环检测条件是否满足会更好。下面是一段标准的使用 wait 和 notify 方法的代码:

// The standard idiom for using the waitmethodsynchronized (obj) {while (condition does not hold)

obj.wait(); // (Releases lock, andreacquires on wakeup)... // Perform action appropriate to condition}

参见 EffectiveJava 第 69 条,获取更多关于为什么应该在循环中来调用 wait 方法的内容。

7、什么是多线程环境下的伪共享(false sharing)?

伪共享是多线程系统(每个处理器有自己的局部缓存)中一个众所周知的性能问题。伪共享发生在不同处理器的上的线程对变量的修改依赖于相同的缓存行。

8、Java 中应该使用什么数据类型来代表价格?

如果不是特别关心内存和性能的话,使用BigDecimal,否则使用预定义精度的 double 类型。

9、怎么将 byte 转换为 String?

可以使用 String 接收 byte[] 参数的构造器来进行转换,需要注意的点是要使用的正确的编码,否则会使用平台默认编码,这个编码可能跟原来的编码相同,也可能不同。

10、我们能将 int 强制转换为 byte 类型的变量吗?如果该值大于 byte 类型的范围,将会出现什么现象?

是的,我们可以做强制转换,但是Java 中 int 是 32 位的,而 byte 是 8 位的,所以,如果强制转化是,int 类型的高 24 位将会被丢弃,byte 类型的范围是从 -128 到 128。

11、哪个类包含 clone 方法?是 Cloneable 还是 Object?

java.lang.Cloneable 是一个标示性接口,不包含任何方法,clone 方法在 object 类中定义。并且需要知道 clone() 方法是一个本地方法,这意味着它是由 c 或 c++ 或 其他本地语言实现的。

12、Java 中 ++ 操作符是线程安全的吗?

不是线程安全的操作。它涉及到多个指令,如读取变量值,增加,然后存储回内存,这个过程可能会出现多个线程交差。

13、a = a + b 与 a += b 的区别

+= 隐式的将加操作的结果类型强制转换为持有结果的类型。如果两这个整型相加,如 byte、short 或者 int,首先会将它们提升到 int 类型,然后在执行加法操作。如果加法操作的结果比 a 的最大值要大,则 a+b 会出现编译错误,但是 a += b 没问题,如下:

byte a = 127;byte b = 127;b = a + b; // error : cannot convert from int to byteb += a; // ok(译者注:这个地方应该表述的有误,其实无论 a+b的值为多少,编译器都会报错,因为 a+b 操作会将 a、b 提升为 int 类型,所以将 int 类型赋值给 byte 就会编译出错)。

14、我能在不进行强制转换的情况下将一个 double 值赋值给 long 类型的变量吗?

不行,你不能在没有强制类型转换的前提下将一个 double 值赋值给 long 类型的变量,因为 double 类型的范围比 long 类型更广,所以必须要进行强制转换。

15、为什么 Java 中的 String 是不可变的(Immutable)?

Java 中的 String 不可变是因为 Java 的设计者认为字符串使用非常频繁,将字符串设置为不可变可以允许多个客户端之间共享相同的字符串。

16、集合类:List和Set比较,各自的子类比较(ArrayList,Vector,LinkedList;HashSet,TreeSet)

List和Set都继承自Collection。

List是有序的,元素可以重复,每个元素都有自己的索引。

Set是无序的,元素不能重复,存入和取出的顺序不一定一致。线程不同步,底层使用Map实现,可以使用ConcurrentHashMap的方式实现线程安全的Set。

ArrayList:底层是数组实现,查询快,增删慢,线程不同步。

LinkedList:底层有链表实现,查询慢,增删快,线程不同步。

Vector:底层是数组,线程同步,用了synchronized关键字修饰,现在用的是他的枚举。

HashSet:底层是哈希表结构,根据hashCode和equals方法确定唯一性。

hashCode和equals:作用一样,都是用来比较两个对象是否一致。equals比较的比较全面,而hashCode只是生成一个hash值进行比较,效率比较高但是不是绝对可靠,而equals是绝对可靠的,equals()比较相等的两个对象,hashCode()一定是相等的;而hashCode()比较相等的对象,equals()比较不一定相等。

TreeSet: 底层是二叉树,对集合中的进行自然顺序排序。

17、HashMap的底层实现,ConcurrentHashMap的底层实现

HashMap的底层由数组和链表两种数据结构存储数据。

数组存储区间是连续的,所以空间复杂度高,但是二分法查找速度快,时间复杂度低O(1),所以寻址容易,插入和删除困难。

链表存储区间不连续,所以空间复杂度低,但是时间复杂度很高O(n),所以寻址复杂,插入和删除简单。

综合两种数据结构的有限,哈希表就产生了,既满足了查找速度快,占用的空间也不大。

哈希表可以说是数组链表,底层是数组,但是数组每一项就是一个链表。

在数组中,每个元素存储的是链表的头,元素存储位置一般通过hash(key)%len活得,也就是元素的的key的哈希值对数组长度取模得到。

HashMap的构造函数,HashMap():构造一个具有默认初始容量(16)和默认加载因子(0.75)的HashMap;

HashMap(int initialCapacity) 构造一个带指定初始容量和默认加载因子(0.75)的空HashMap;

HashMap(int initialCapacity,float loadFactor)构造一个指定初始容器和加载因子的HashMap;

当执行put操作时,HashMap会判断要存储内容的key值是否为null,如果为null,则执行putForNullKey()方法,这个方法将内容存储到Entry[]数组的第一个位置,如果key不为null,这计算key的hash值,然后对数组长度取模,得到存储位置的下表,再迭代该数组元素上的链表,看该链表上是否有与改hash值相同的,如果有hash值相同,则会直接覆盖value的值,如果没有hash值相同,就将该内容放在链表头,最先放入的内容会放在链表尾。当HashMap中存储的内容操作数组的长度*loadFactor时,数组就会进行扩容操作。扩容比较消耗,所以最好是知道hashMap中的元素的个数,预设元素个数,提高HashMap的存储效率。

执行get操作,就是根据key的hash值找到数组中对应的位置,然后遍历链表,返回对应key的value。

遍历HashMap时,使用HashMap的匿名内部类Entry遍历比使用keySet()效率高很多,keySet()遍历了两次,一次装维iterator,一次是从hashMap中去取出key对应的value,二entrySet只遍历了一次,他把key和value都放在了entry中。

ConcurrentHashMap提供了更好的并发能力,降低了对读一致性的要求。允许多个修改操作并发执行,关键在于使用锁分离技术。它使用多个锁来控制hash表的不同部分的修改。ConcurrentHashMap内部使用segment来表示这些不同部分。每个segment就是一小段ConcurrentHashMap,他们有自己的锁。

ConcurrentHashMap中有需要跨段的方法size(),contaisValue(),他们可能需要锁住整张hash表来实现,这需要按照顺序锁定所有的段,操作完毕后,又按照顺序释放完所有的段,按顺序很重要,否则会出现是说的情况。ConcurrentHashMap内部,段数组是final的。并且其成员变量都是final的。

Segment继承了ReentrantLock,表明每个segement都可以当做一个锁。 

18、如何实现HashMap顺序存储:可以参考LinkedHashMap的底层实现

使用双向链表, 这就要归功于LinkedHashMap中的一个数据结构—Entry header了,header是一个双向链表中的首节点,该双向链表保存了entry插入的顺序,在迭代时,实际上是在迭代该双向链表。每次调用put()方法时,第一步和HashMap的put()方法一致,第二步就是将该元素的before节点指向header的before节点,after节点指向header,将header的before节点指向该元素,以完成双向链表的记录顺序。

19、HashTable和ConcurrentHashMap的区别

都是线程安全的。

HashTable锁整个表,当容量达到一定范围后,遍历时间就会很长,锁定时间就很长,效率低。

ConcurrentHashMap使用锁分段技术,只是锁定一段hash表,不影响其他段的访问,效率高,

20、String,StringBuffer和StringBuilder的区别

都是字符串常量

String是final修饰的,不可变的,拼接字符串用"+",

StringBuffer线程安全的,类似于String的字符串缓冲区,拼接字符串用 append(),insert()方法,append() 方法始终将这些字符添加到缓冲区的末端;而 insert 方法则在指定的点添加字符,效率较慢。

StringBuilder是线程不安全的,类似于String的字符串缓冲区,拼接字符串用append(),insert()方法,单线程使用时和StringBuffer是一样的。效率较快。

21、Object的方法有哪些:比如有wait方法,为什么会有

equals();比较对象相等。

hashCode();返回hash值。

toString();返回对象的字符串表示。

clone();返回对象的一个副本。

wait();让当前线程等待。

notify();唤醒在此对象监视器上等待的单个线程。

notifyAll();唤醒在此对象监视器上等待的所有线程。

getClass();获取改对象的运行类。

finalize();改对象的垃圾回收器进行调用。

22、wait和sleep的区别

wait()是Object的方法,会释放对象锁,使用notify()唤醒进入对象锁定池准备。

sleep()是Thread的方法,不会释放对象锁,在睡眠了指定的时间后,又恢复正常运行

23、JVM的内存结构,JVM的算法

虚拟机栈、本地方法栈、堆、方法区、程序计数器。

标记清除算法,标记整理算法,复制算法、分代收集算法。

24、强引用,软引用和弱引用的区别

强引用:对象不会被回收

软引用:当内存快要溢出之前,将会被标记在回收范围内,在第二次回收时进行回收

弱引用:在下一次回收时将会被回收

虚引用:不会构成影响,也无法根据弱引用来活得一个对象。

25、数组在内存中如何分配

栈,存局部变量

堆或方法区,存对象,连续的指定大小的内存

数组名存的是堆中的数组对象的地址,根据数组对象地址和对应元素的索引可以获取值。

26、springmvc的核心是什么,请求的流程是怎么处理的,控制反转怎么实现的

核心是中央处理器-前端控制器。

前端控制器,接收请求,根据映射处理器找到处理器适配器,处理器适配器执行找到处理器,然后处理器处理请求后,返回数据到前端控制器,前端控制器将数据modelAndView给视图解析器,将view返回到前端控制器,前端控制器将view渲染数据后返回一个view。

控制反转,是一种设计思想,Spring的容器控制对象的生命周期和对详见的关系,所有类在Spring容器中登记,所有类的创建、销毁都由Spring来控制。而不是传统的在对象内部直接控制。能解除耦合,功能复用,同时代码结构更加灵活。

27、spring里面的aop的原理是什么

面向切面编程,利用“横切”的技术,剖开封装对象的内部,滨江那些影响多各类的公共行为封装到一个可重用的模块,这就是Aspect。就是将那些与业务无关,却为业务模块说停工共同调用的逻辑或责任封装起来,减少系统的重复代码,降低模块之间的耦合度,有利于维护。

横切是将软件分为核心关注点和横切关注点。横切关注点经常发生在核心关注点的多处,而且各处基本相似,如权限认证、事务、日志等。

spring的AOP待了由IOC容器负责生成、管理,其依赖关系也由 IOC负责管理。

默认使用java动态代理来创建AOP代理,当需要代理的类不是代理接口的时候,Spring会切换使用GGLIB代理

28、java的多态表现在哪里

编译时多态,重载

运行时多态,重写,需要继承;上溯造型

29、接口有什么用

提供了一个统一的操作方法名,用同一个方法名在不同类中可以实现不一样的具体过程。

通过接口可以实现不相关类的相同行为,而不需要了解对象所对应的类。

通过接口可以致命多个类需要实现的方法。

通过接口可以了解对象的交互界面,而不需了解对象所对应的类。

30、说说http,https协议

http是一个属于应用层的面向对象的协议,简捷、快速,

http支持客户/服务器模式。简单快速,向服务器请求时,只需传递请求方法和路径。常用方法有GET,POST,HEAD,由于协议简单,所以效率高,速度快。灵活,http允许传输任意类型的数据对象。无连接,限制每次连接只处理一个请求,收到客户的应答后就断开连接,节省传输时间。无状态,对于事务处理没有记忆能力,如果后续需要处理前面的信息,则它必须重传,这样可能会增大传输的数据量,服务器不需要先前信息时,应答比较快。

https协议是基于SSL的http协议,使用了http协议,但是不同于http的默认端口和加密,身份验证层。https是一个安全通信通道,用于在客户计算机和服务器之间交换信息,使用安全套接字层(SSL)进行信息交换,是http的安全版。

客户端在使用HTTPS方式与Web服务器通信时有以下几个步骤。

(1)客户使用https的URL访问Web服务器,要求与Web服务器建立SSL连接。

(2)Web服务器收到客户端请求后,会将网站的证书信息(证书中包含公钥)传送一份给客户端。

(3)客户端的浏览器与Web服务器开始协商SSL连接的安全等级,也就是信息加密的等级。

(4)客户端的浏览器根据双方同意的安全等级,建立会话密钥,然后利用网站的公钥将会话密钥加密,并传送给网站。

(5)Web服务器利用自己的私钥解密出会话密钥。

(6)Web服务器利用会话密钥加密与客户端之间的通信。

https解决的问题:信任主机的问题;通讯过程中的数据的泄密和被窜改;少许对客户端有要求的情况下,会要求客户端也必须有一个证书。

31、tcp/ip协议簇;

TCP/IP 是一类协议系统,它是用于网络通信的一套协议集。

 在TCP/IP中协议数据先由上往下将数据装包,然后由下往上拆包。

32、tcp,udp区别

TCP的优点: 可靠,稳定 TCP的可靠体现在TCP在传递数据之前,会有三次握手来建立连接,而且在数据传递时,有确认、窗口、重传、拥塞控制机制,在数据传完后,还会断开连接用来节约系统资源。 TCP的缺点: 慢,效率低,占用系统资源高,易被攻击 TCP在传递数据之前,要先建连接,这会消耗时间,而且在数据传递时,确认机制、重传机制、拥塞控制机制等都会消耗大量的时间,而且要在每台设备上维护所有的传输连接,事实上,每个连接都会占用系统的CPU、内存等硬件资源。 而且,因为TCP有确认机制、三次握手机制,这些也导致TCP容易被人利用,实现DOS、DDOS、CC等攻击。

UDP的优点: 快,比TCP稍安全 UDP没有TCP的握手、确认、窗口、重传、拥塞控制等机制,UDP是一个无状态的传输协议,所以它在传递数据时非常快。没有TCP的这些机制,UDP较TCP被攻击者利用的漏洞就要少一些。但UDP也是无法避免攻击的,比如:UDP Flood攻击…… UDP的缺点: 不可靠,不稳定 因为UDP没有TCP那些可靠的机制,在数据传递时,如果网络质量不好,就会很容易丢包。 基于上面的优缺点,那么: 什么时候应该使用TCP: 当对网络通讯质量有要求的时候,比如:整个数据要准确无误的传递给对方,这往往用于一些要求可靠的应用,比如HTTP、HTTPS、FTP等传输文件的协议,POP、SMTP等邮件传输的协议。 在日常生活中,常见使用TCP协议的应用如下: 浏览器,用的HTTP FlashFXP,用的FTP Outlook,用的POP、SMTP Putty,用的Telnet、SSH QQ文件传输 ………… 什么时候应该使用UDP: 当对网络通讯质量要求不高的时候,要求网络通讯速度能尽量的快,这时就可以使用UDP。

小结TCP与UDP的区别:

(1)基于连接与无连接;

(2)对系统资源的要求(TCP较多,UDP少);

(3)UDP程序结构较简单;

(4)流模式与数据报模式 ;

(5)TCP保证数据正确性,UDP可能丢包,TCP保证数据顺序,UDP不保证。

33、说说tcp三次握手,四次挥手

34、cookie和session的区别,分布式环境怎么保存用户状态

cookie存在浏览器,在客户端,不是很安全,单个cookie保存数据不能操作4k。cookie保存字符串,cookie设置了路径参数,在不同路径下是不能访问的。如果不设置周期,那就是默认为会话期间有效,关闭窗口,cookie就失效

session存在服务器,在服务器端,session可以通过session id来获取,如果找到了对应的session,就将session返回给客户端,如果服务器没有找到对应的session,会重新创建一个。session会在本次相应中返回给客户端保存。session id可以保存在cookie中。session会在一定时间内保存在服务器上,当访问增多,会占用服务器的性能。session保存对象。session不区分路径,所以session在任何地方都可以访问

分布式环境可以基于数据库的Session共享,基于NFS共享文件系统,基于tomcat web容器本身的session复制共享,基于redis进行session共享,基于cookie进行session共享。

35、git,svn区别

git是分布式的,强调个体,公共服务期和数据量都不会太大,速度快,灵活,很容易解决冲突,离线工作。但是学习周期相对较长,不适合常规思维,代码保密性差。

svn是集中式的,管理方便,逻辑明确;易于管理,集中式服务器更能保证安全,代码一致性高,适合人数不多的项目开发。但是服务器压力大,数据库容量暴增;如果连不上服务器,就不能工作;不适合开源开发。

36、请写一段栈溢出、堆溢出的代码

    栈溢出:

    while(true){

         ArrayList list=new ArrayList (2000);

       }

    堆溢出:

    publicclassOOME{

    static class OOMObject{ }

    publicstaticvoidmain(String [] args) {

        List list =newArrayList();

        while(true){

            list.add(newOOMObject());

        }

    }

}

37、ThreadLocal可以用来共享数据吗

ThreadLocal使用场合主要解决多线程中数据数据因并发产生不一致问题。ThreadLocal为每个线程的中并发访问的数据提供一个副本,通过访问副本来运行业务,这样的结果是耗费了内存,单大大减少了线程同步所带来性能消耗,也减少了线程并发控制的复杂度。

ThreadLocal和Synchonized都用于解决多线程并发访问。但是ThreadLocal与synchronized有本质的区别。synchronized是利用锁的机制,使变量或代码块在某一时该只能被一个线程访问。而ThreadLocal为每一个线程都提供了变量的副本,使得每个线程在某一时间访问到的并不是同一个对象,这样就隔离了多个线程对数据的数据共享。而Synchronized却正好相反,它用于在多个线程间通信时能够获得数据共享。

Synchronized用于线程间的数据共享,而ThreadLocal则用于线程间的数据隔离。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,417评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,921评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,850评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,945评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,069评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,188评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,239评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,994评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,409评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,735评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,898评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,578评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,205评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,916评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,156评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,722评论 2 363
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,781评论 2 351

推荐阅读更多精彩内容