JavaSE面试题之异常及Java并发编程之Copy-On-Write容器[图]

一、JavaSE面试题:异常
主要总结了JavaSE中异常类相关面试题,在后续,会沿着第一篇开篇的知识线路一直总结下去,做到日更!如果我能做到百日百更,希望你也可以跟着百日百刷,一百天养成一个好习惯。
Q:
说一下Java中的异常体系?
Q:
Error和Exception的区别?
Error(错误):
系统中的错误,是在程序编译时出现的错误,只能通过修改程序才能修正。一般是指与虚拟机相关的问题,如系统崩溃,虚拟机错误,内存空间不足,方法调用栈溢等。
Exception(异常):
表示程序可以处理的异常,可以捕获且可能恢复。遇到这类异常,应该尽可能处理异常,使程序恢复运行,而不应该随意终止异常。

JavaSE面试题之异常及Java并发编程之Copy-On-Write容器[图]

Q:
写出你最常见的5个RuntimeException?
(1)java.lang.NullPointerException空指针异常;出现原因:调用了未经初始化的对象或者是不存在的对象。
(2)java.lang.ClassNotFoundException指定的类找不到;出现原因:类的名称和路径加载错误;通常都是程序
试图通过字符串来加载某个类时可能引发异常。
(3)java.lang.NumberFormatException字符串转换为数字异常;出现原因:字符型数据中包含非数字型字符。
(4)java.lang.IndexOutOfBoundsException数组角标越界异常,常见于操作数组对象时发生。
(5)java.lang.IllegalArgumentException方法传递参数错误。
(6)java.lang.ClassCastException数据类型转换异常。
Q:
如何处理异常?
异常的处理方式有两种:
处理。
向上抛,交给调者处理。
具体的处理方式的选择原则:
自己明确的知道如何处理的,就要处理掉。
不知道如何处理的,就交给调者处理。
注:异常,不能捕获了之后什么也不做。或者只是使e.printStacktrac
Q:
try()里面有个return语句,那么后面的finally{}里面的代码会不会被执行?什么时候执行,return前还是return后?
如果try中有return语句,那么finally中的代码还是会执。
因为return表示的是要整个方法体返回,所以,finally中的语句会在return之前执。
但是return前执行的finally块内,对数据的修改效果对于引用类型和值类型会所不同:
1//测试修改值类型23staticintf(){45intret=0;67try{89returnret;//返回0,finally内的修改效果不起作用1011}finally{1213ret++;1415System.out.println("finally执行");1617}1819}20212223//测试修改引用类型2425staticint[]f2(){2627int[]ret=newint[]{0};2829try{3031returnret;//返回[1],finally内的修改效果起了作用3233}finally{3435ret[0]++;3637System.out.println("finally执行");3839}4041
Q:
调用下面的方法,得到的返回值是什么?
1publicintgetNum(){23try{45inta=1/0;67return1;89}catch(Exceptione){1011return2;1213}finally{1415return3;1617}1819}
返回值为3。
代码在走到第3行的时候遇到了一个MathException,这时第四行的代码就不会执行了,代码直接跳转到catch语句中,走到第6行的时候,异常机制有这么一个原则如果在catch中遇到了return或者异常等能使该函数终止的话那么有finally就必须先执行完finally代码块里面的代码然后再返回值。因此代码又跳到第8行,可惜第8行是一个return语句,那么这个时候方法就结束了,因此第6行的返回结果就无法被真正返回。如果finally仅仅是处理了一个释放资源的操作,那么该道题最终返回的结果就是2。因此上面返回值是3。
Q:
throw和throws的区别?
throw:
throw语句用在方法体内,表示抛出异常,由方法体内的语句处理。
throw是具体向外抛出异常的动作,所以它抛出的是一个异常实例,执行throw一定是抛出了某种异常。
throws:
throws语句是用在方法声明后面,表示如果抛出异常,由该方法的调用者来进行异常的处理。
throws主要是声明这个方法会抛出某种类型的异常,让它的使用者要知道需要捕获的异常的类型。
throws表示出现异常的一种可能性,并不一定会发生这种异常。
二、Java并发编程之Copy-On-Write容器
前面两篇讲了并发编程中线程安全HashMap:
ConcurrentHashMap
,那么作为同样使用频率很高的List和Set,J.U.C当然也提供了相应的线程安全集合,就是
Copy-On-Write
容器
CopyOnWriteArrayList

CopyOnWriteArraySet

COW设计思想
源码分析
应用场景
1.COW思想
这里的COW当然不是奶牛,而是
Copy-On-Write
的简称,即写时复制,是一种用于程序设计中的优化策略。
1.1COW原理
COW的基本思路:
当读取共享数据时,直接读取,不需要有其他操作(比如阻塞等待、复制等)。
当写共享数据时,将旧数据复制出来一份作为新数据,只修改新数据,修改完新数据之后将新数据的引用赋值给原来数据的引用。在整个写数据的过程中,所有读取共享数据的操作都是读的旧数据。
COW容器只有写操作与写操作之间是互斥的,读读和读写都不互斥。
1.2COW优缺点分析
优点:
效率高。因为COW保证读和写操作的不是同一份数据,共享数据在读和写时都不需要阻塞其他来读取数据的线程,所以COW有很高的效率。
保证数据一致性。因为COW保证读和写操作的不是同一份数据,读数据的操作不会读到写了一半的数据,所以能够保证数据的最终一致性。
缺点:

数据实时性差。COW在写数据完成之前一直读取旧数据,而写数据又包括复制和修改的操作,花费时间较长,导致数据实时性较差。其实COW的设计思想就是通过牺牲数据的实时性来保证数据一致性的。作文(https://www.isanxia.com)存占用大。COW中有一步复制操作,将旧数据复制出来一份作为新数据,假如旧数据本身比较大,那么新数据也要占用同样大的内存空间。类似空间换时间的思想,这里用空间换数据一致性,当然也换取了读取数据的时间。

1.3COW应用
COW的设计思想的一些应用:内存管理(如Linux的fork()函数),数据存储(如redis),文件管理系统(如Linux的文件管理系统),软件开发(如Java的Copy-On-Write容器)。
2.源码分析
理解了
Copy-On-Write
思想,
CopyOnWriteArrayList

CopyOnWriteArraySet
的源码就很容易了。本文以
CopyOnWriteArrayList
源码为例来分析
Copy-On-Write
容器。
2.1类结构
CopyOnWriteArrayList
只有两个属性,数组array用于存储数据,重入锁lock用于写操作的同步。
publicclassCopyOnWriteArrayList<E>implementsList<E>,RandomAccess,Cloneable,java.io.Serializable{finaltransientReentrantLocklock=newReentrantLock();privatetransientvolatileObject[]array;}
2.2get()
get()方法获取数据,真的不用注释和讲解,最简单的代码。唯一需要注意的一点就是get()方法是没有加锁的,不需要同步,读数据线程一定不会阻塞。
publicEget(intindex){returnget(getArray(),index);}finalObject[]getArray(){returnarray;}privateEget(Object[]a,intindex){return(E)a[index];}
2.3add()
代码很简单,基本过程就是按照COW思想的操作步骤:
lock锁同步
旧数组复制出一个新数组
新数组添加元素
新数组引用赋给array
publicbooleanadd(Ee){finalReentrantLocklock=this.lock;lock.lock();//1.lock锁同步try{//2.旧数组复制出一个新数组Object[]elements=getArray();intlen=elements.length;Object[]newElements=Arrays.copyOf(elements,len+1);//3.新数组添加元素newElements[len]=e;//4.新数组引用赋给arraysetArray(newElements);returntrue;}finally{lock.unlock();//解锁}}
3.应用场景
Copy-On-Write并发容器用于读多写少的并发场,如商品的访问和更新,排行榜,白名单/黑名单等。
举例:一个充值排行榜的功能,排行榜会有很多人查看访问,但是只有充值之后才会修改排行榜上的数据,或者充值之后也不更新,只有每天晚上9点更新排行榜,标准的读多写少。
publicclassCopyOnWriteArrayListTest{publicstaticCopyOnWriteArrayList<Integer>rankIds=newCopyOnWriteArrayList<Integer>();publicstaticvoidaddRankIds(intid){/**获取id在rankIds中的排序,代码省略*假设id应该在排行榜中的第一个*/rankIds.add(0,id);}}
4.总结
Copy-On-Write并发容器处理并发问题的原理:
当读取共享数据时,直接读取,不需要有其他操作(比如阻塞等待、复制等)。
当写共享数据时,将旧数据复制出来一份作为新数据,只修改新数据,修改完新数据之后将新数据的引用赋值给原来数据的引用。在整个写数据的过程中,所有读取共享数据的操作都是读的旧数据。
源码的并不只在于学习编程方法,更重要的是理解源码的设计思想,能够在开发和设计中运用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值